Practice| 面向对象

实参与形参的传递机制

* 实参给形参赋值:
* 1、基本数据类型:
* 实参给形参的数据值,形参的修改和实参无关
* 2、引用数据类型
* 实参给形参的地址值,如果这个地址值修改“属性”会影响实参,但是你如果修改是地址值,和实参无关了
*/

class MianShiTi{
    String str = new String("good idear"); //创建字符串对象;
    char[] ch = {'a','b','c','d'}; //创建数组;
    
    public static void main(String[] args){
        MianShiTi m = new MianShiTi(); //创建一个对象;
        
        exchange(m.str, m.ch);
        //m.str没有变,m.ch的[1]变了
        System.out.println(m.str); //good idear ,它们是两个无关的str
        System.out.println(m.ch); //a*cd
    
    
    
        String s = "bbbb";
        StringBuffer b = new StringBuffer("bbbb");
        change(s,b);
        //s不可变,s仍然"bbbb"
        //b的内容就从"bbbb" ---> "aaaa"
        System.out.println(s+b); //bbbbaaaa
    
    }

    public static void exchange(String str, char[] ch){ //两个都是引用数据类型String和char[]数组,
        str = "Hello World"; //字符串对象是不可变的,一旦修改str=xxx,就是产生新的对象,和原来的"实参"无关
        System.out.println(str); //Hello World
        ch[1] = '*';  //数组元素是可变的,ch形参和上面的m.ch实参指向的是同一个数组,所以ch[1]修改,就是修改m.ch[1]
        System.out.println(ch); //a*cd
    }
    
    
    private static void change(String s, StringBuffer b){  //两个形参为String类型和 类 都是引用数据类型
        s = "aaa";
        b.setLength(0);//b的长度设置为0,相当于清空原来b中内容
        b.append("aaaa");//append表示追加,又追加了aaaa
    }
    
    
    
}
public class MainTest{
    public static void test(String str){
        str = "hello";
    }
    public static void main(String[] args){
        String str = "beijing"; 
        test(str);
        System.out.println(str);  //beijing
    }
}
public class TestMethod {

    //i,str,j是形参
        public static void change(int i, String str, Integer j, MyData my){
            i++;//这里i无论怎么改,和实参无关
            str += "尚硅谷";//字符串对象是不可变的,一旦改变,会产生新对象,str中的地址值变了
            j++;//Integer对象是不可变的,一旦改变,会产生新对象,j中的地址值变了
            //my.num = 20;
            my = new MyData();
            my.num = 100;
        }
        public static void main(String[] args){
            int a = 10;
            String s = "hello";
            Integer b = 20;
            MyData m = new MyData();
            
            change(a,s,b,m);//a,s,b,m是实参
            
            System.out.println("a = " + a); //a=10
            System.out.println("s = " + s); //s=hello
            System.out.println("b = " + b); //b=20
            System.out.println("m.num = " + m.num); //n.num=100
    }
}
class MyData{
    int num = 10;
}
View Code
class TEXT{
    public int num;
    public String str;
    
    public TEXT(int num, String str){
        this.num = num;
        this.str = str;
    }
}
public class Class4 {
    public static void f1(TEXT tIn, int intIn, Integer integerIn, String strIn){
        tIn.num =200;
        tIn.str = "bcd";
        intIn = 200;
        integerIn = 200;
        strIn = "bcd";
    }
    public static void main(String[] args) {
        TEXT tIn = new TEXT(100, "abc");  //tIn引用数据类型,对象
        int intIn = 100; 
        Integer integerIn = 100; 
        String strIn = "abc";
        
        f1(tIn,intIn,integerIn,strIn);
                            //引用数据类型 + 引用数据类型+int+Integer +String
        System.out.println(tIn.num + tIn.str + intIn + integerIn + strIn);
    }                       //200 bcd + 100 + 100 + abc
}

===>>>200bcd100100abc
View Code

 

用数组来管理属性、对象等

/*
(1)声明一个日期类型MyDate:有属性:年year,月month,日day
(2)创建2个日期对象,分别赋值为:你的出生日期,你对象的出生日期,放到数组中
(3)遍历显示
*/
public class TestMydate {

    public static void main(String[] args) {
        MyDate[] arr = new MyDate[2]; //创建长度为2的数组
        
        arr[0] = new MyDate();  //引用数据类型需要给它赋值一个对象;
        
        arr[0].year = 1994;
        arr[0].month = 7;
        arr[0].day = 7;
        
        arr[1] = new MyDate();
        arr[1].year = 1996;
        arr[1].month = 7 ;
        arr[1].day = 7;
        
        for(MyDate num : arr){
            System.out.println(num.year + "-" + num.month + "-" + num.day);
        }
        
View Code
class TestTeacher{
    public static void main(String[] args){

        //用数组来管理属性,创建的对象,排序等
        Teacher[] arr = new Teacher[5];  //声明一个一维数组,来存储5个Teacher的对象; 
        arr[0] = new Teacher();         //arr[0]代表一个元素,是Teacher类型(引用数据类型),需要赋值为一个Teacher对象;
        arr[0].name = "kris";
        arr[0].age = 18;
        arr[0].gender = '男';
        arr[0].course = "java";
        
        Teacher t2 = new Teacher();
        t2.name = "alex";
        t2.age = 11;
        t2.gender = '女';
        t2.course = "Mysql";
        arr[1] = t2;
        
        for(int i = 0;i < arr.length;i++){
            //arr[i]是一个Teacher的对象
            //Exception in thread "main" java.lang.NullPointerException空指针异常
            //一旦报NullPointerException,说明对象是null
            //arr[i]是否是null?
            //if(arr[i] != null){
                System.out.println(arr[i].name + "	" + arr[i].age + "	" + arr[i].gender + "	" +arr[i].course);
            //}
            
        }
        
    }
}

class Teacher{
    String name;
    int age;
    char gender;
    String course;
}
练习2
声明一个圆类Circle,有属性半径radius
声明一个测试类TestCircleArray,
在main方法中,创建一个Circle数组,长度为3,并创建三个Circle对象放到数组中,
遍历显示数组,显示每一个圆的半径、面积。
然后在对Circle数组进行排序,按照半径从小到大,再次遍历显示数组,显示每一个圆的半径、面积
*/

class TestCircle2{
    public static void main(String[] args){
        
        Circle[] arr = new Circle[3]; //创建一个Circle数组,长度为3,默认值都为null
        
        //创建3个Circle对象放到数组中,   动态输入创建
        java.util.Scanner input = new java.util.Scanner(System.in);
        for(int i = 0; i < arr.length;i++){
            arr[i] = new Circle(); //先创建圆Circle的对象
            System.out.print("请输入圆的半径:");
            arr[i].radius = input.nextDouble();
            System.out.println("半径" + arr[i].radius + "	" + "面积" + Math.PI * arr[i].radius * arr[i].radius);
        }
        /* //静态输入
        arr[0] = new Circle();
        arr[1] =  new Circle();
        arr[2] =  new Circle();
        
        arr[0].radius = 2.0;
        arr[1].radius = 3.0;
        arr[2].radius = 1.0;
        */
        //冒泡排序按从小到大顺序排,需要排arr.length-1次,大的就往后
        //第一轮:i=1,j=0,1两次
        //第二轮:i=2,j=1一次
        for(int i = 1; i < arr.length;i++){
            for(int j = 0;j < arr.length-i;j++){ //如果前面的圆的半径比较后面的圆的半径大,就交换两个圆
                if(arr[j].radius > arr[j+1].radius){  //比较的是圆的半径,对象需要.半径属性
                    Circle temp = arr[j];//temp的类型和arr[j]和arr[j+1]一样,它俩是Circle
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
            
        }
        
        for(int i = 0; i < arr.length;i++){
            System.out.println(arr[i].radius);
        }
    }

}
class Circle{
    double radius;

}
练习3
(1)声明一个丈夫类型Husband,有属性:姓名,年龄,妻子,其中妻子是Wife类型
(2)声明一个妻子类型Wife,有属性:姓名,年龄,丈夫,其中丈夫是Husband类型
(3)创建一个丈夫对象,创建一个妻子对象,并显示他们的信息

*/
class Test3{
    public static void main(String[] args){
        
        Husband hus = new Husband(); //hus丈夫对象;
        hus.name = "kris"; 
        hus.age = 20; 
        
        Wife wif = new Wife();         //wif妻子对象;
        wif.name = "xka";
        wif.age = 19;
        
        hus.qi = wif;   //qi为引用数据类型,必须给它赋值一个对象;
        wif.fu = hus;
        
        System.out.println("丈夫的信息:"+hus.name + "	" + hus.age + "	" + "妻子的信息:" + hus.qi.name + hus.qi.age);
        System.out.println("妻子的信息:" + wif.name + "	" + wif.age + "	" +"丈夫的信息:"+ wif.fu.name);
        
    }
}


class Husband{
    String name;
    int age;
    Wife qi;

}

class Wife{
    String name;
    int age;
    Husband fu;

}
/*
2、练习2
(1)声明一个日期类型MyDate,包含年、月、日
(2)声明一个员工类,包含属性:姓名、薪资、生日,其中生日是MyDate类型
(3)声明一个测试类,在main方法中,声明一个数组,创建三个员工对象,并为属性赋值
(4)遍历显示员工信息,并且按照生日排序
(5)遍历显示员工信息,按照薪资排序
*/

class Test2{
    public static void main(String[] args){
        Staff[] arr = new Staff[3]; //声明一个数组,创建员工对象,并为他们赋值;
        
        java.util.Scanner input = new java.util.Scanner(System.in);
        
        for(int i = 0; i < arr.length; i++){
            arr[i] = new Staff();
            System.out.print("请输入员工姓名:");
            arr[i].name = input.next();
            System.out.print("员工薪资:");
            arr[i].salary = input.nextInt();
            System.out.println("请输入员工生日");
            arr[i].birthday = new MyDate();  //birthday为引用数据类型,必须给它赋值一个对象;
            System.out.print("年:");
            arr[i].birthday.year = input.nextInt();
            System.out.print("月:");
            arr[i].birthday.month = input.nextInt();
            System.out.print("日:");
            arr[i].birthday.day = input.nextInt();
        }
        System.out.println("姓名	" + "薪资	" + "生	日");
        //遍历显示员工信息;foreach循环
        //for(元素的数据类型 元素名 : 数组名){}
        for(Staff num : arr){
            //System.out.println(arr[i].name + "	" + arr[i].salary + "	" + arr[i].birthday.year + "-" + arr[i].birthday.month + "-" + arr[i].birthday.day);
            System.out.println(num.name + "	" + num.salary + "	" + num.birthday.year + "-" + num.birthday.month + "-" + num.birthday.day);
        }
        
        
        
        //冒泡排序;按员工生日排序;从小到大
        for (int j = 1;j < arr.length;j++){
            
            for(int i = 0;i < arr.length-i; i++){
                
                if(arr[i].birthday.year > arr[i+1].birthday.year){ //先比较年year,大的年龄小
                Staff temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }else if(arr[i].birthday.year == arr[i+1].birthday.year){
                if(arr[i].birthday.month > arr[i+1].birthday.month){
                    Staff temp = arr[i];
                    arr[i] = arr[i+1];
                    arr[i+1] = temp;
                }else if(arr[i].birthday.month == arr[i+1].birthday.month){
                    if(arr[i].birthday.day > arr[i+1].birthday.day){
                    Staff temp = arr[i];
                    arr[i] = arr[i+1];
                    arr[i+1] = temp;
                        }
                    }
                }
            }
        }
        //遍历排序之后的
        System.out.println("排序之后的:");
        System.out.println("姓名	" + "薪资	" + "生	日");
        for(int i = 0;i < arr.length; i++){
            
            System.out.println(arr[i].name + "	" + arr[i].salary + "	" + arr[i].birthday.year + "-" + arr[i].birthday.month + "-" + arr[i].birthday.day);
        }
    }

}
class MyDate{
    int year;
    int month;
    int day;
    
}
class Staff{
    String name;
    double salary;
    MyDate birthday;
    
}

类的继承,super

1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:账号id,余额balance,年利率annualInterestRate;
包含的方法:访问器方法(getter和setter方法),返回月利率的方法getMonthlyInterest(),取款方法withdraw(),存款方法deposit()。 写一个测试类TestAccount:在用户程序中,创建一个账号为11223344、余额为20000、年利率4.
5%的Account对象。使用withdraw方法提款30000元,并打印余额。 再使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率。 2、创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额,。在CheckAccount类中重写withdraw方法。 写一个用户程序测试CheckAccount类。在用户程序中,创建一个账号为11223344、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象。 提示: (1)子类CheckAccount的构造方法需要将从父类继承的3个属性和子类自己的属性全部初始化。 (2)父类Account的属性balance被设置为private,但在子类CheckAccount的withdraw方法中需要修改它的值 最后思考:如果将父类Account的属性balance设置为protected,会怎么样?
package com.atguigu.variable;

import com.atguigu.inherited.Account;

public class CheckAccount extends Account {
    
    private double overdraft;

    public CheckAccount() {
        super();
    }

    public CheckAccount(String id, double balance, double annualInterestRate, double overdraft) {
        super(id, balance, annualInterestRate);
        this.overdraft = overdraft;
    }

    public double getOverdraft() {
        return overdraft;
    }

    public void setOverdraft(double overdraft) {
        this.overdraft = overdraft;
    }

    
/*    public void withdraw(double money){
        if(money < 0){
        System.out.println("输入有误");
        }if(money < getBalance()){ 
            super.withdraw(money); //正常取,可以使用父类里边的方法withdraw
        }else{  //可以透支
            if(money > getBalance() + overdraft){
                System.out.println("超过可透支额度");
            }else{
                System.out.println("剩余可透支额度为:" + (overdraft -= money - getBalance())); //取后剩余的透支额度;
                //超过的额度(money - balance);
                setBalance(0);
                System.out.println("哎呀取完了,账户余额为:" + getBalance());
            }
            
        }
    }*/
    
//    如果将父类Account的属性balance设置为protected,表在其他包的子类里边也可以使用
    public void withdraw(double money){
        if(money < 0){
            System.out.println("您的输入有误");
        }if(money < balance){
            super.withdraw(money);  
        }else{
            if(money > balance + overdraft){
                System.out.println("超过卡的取款额度");
            }else{
                System.out.println("可透支额度剩余:" + (overdraft -= money -balance));
                setBalance(0);
            }
        }
    }
    
    
}
package com.atguigu.variable;

import com.atguigu.inherited.Account;

public class TestAccount {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Account a = new Account("11223344", 20000, 0.045);
        CheckAccount c = new CheckAccount("11223344", 20000, 0.056, 5000);
        
        c.withdraw(28000);//传参调用withdraw方法,它是没有返回值的。
        //System.out.println(a.getBalance());
        System.out.println(a.deposit(2000));
    
        
    }

}

 多态转型

// A(show(D obj) show(A obj)) --> B(show(B obj) show(A obj) ) --> C 
//                                                                   --> D
//父类的变量可以存储子类的对象;但子类的变量不能存储父类的对象;   D13Exam
public class Exam1 {
    public static void main(String[] args) {
        A a1 = new A(); 
        A a2 = new B(); //向上转型 a2对象可以调用B中重写父类的方法show(A obj)(重写的形参看是否符合 父类的引用变量接收子类的对象。) 和 父类中的方法。
        B b = new B(); //本态引用,b可以调用它自己即子类B中的方法和继承父类的方法,只要参数符合就可以。
        C c = new C();
        D d = new D();
        System.out.println("(1)" + a1.show(b));//调用A类中的哪个show方法,实参是子类B的对象b,b可以传给它的父类引用变量 A obj 多态参数
    
        System.out.println("(2)" + a2.show(b));//B类的对象有几个show方法? D继承了B,B继承了A; 
//((1)show(D obj)(2)show(A obj)(3)show(B obj)),这里传的实参类型D类型d对象,选择show(D obj)执行
System.out.println("(3)" + b.show(c));//b类的对象有几个方法? b可以调用B和A中所有的方法,形参c 可以传给它的父类;多态参数。 // 这里传的实参类型是C类型的c对象,如果有形参C类型的,肯定首选,这里没有,看哪个合适,选择B类型 System.out.println("(4)" + b.show(d)); // 这里传的实参类型是D类型的d对象,有合适的, } } class A{ public String show(D obj){ return ("A and D"); } public String show(A obj){ //a1对象可以调用哪个传入B类型的show方法呢?B继承了A return "A and A"; } } class B extends A{ public String show(B obj){ return "B and B"; } @Override public String show(A obj){ //重写了父类show(A obj)的方法 return "B and A"; } } class C extends B{ } class D extends B{ ---》》 (1)A and A (2)B and A (3)B and B (4)A and D

多态针对方法的,属性没有多态,注意权限修饰符

public class Exam2 {
    public static void main(String[] args) {
        Base b = new Sub();//多态引用
        System.out.println(b.x);//属性没有多态,按照编译时,b对象有1个x,是Base类中 //1
    }
}
class Base{
    int x = 1;
}
class Sub extends Base{
    int x = 2;
}
View Code
public class Child extends Father{
    public String grade;
    
    public static void main(String[] args){
        Father f = new Child();  //向上转型;
        System.out.println(f.name);//因为name是private的,所以编译错误;
    }
}

class Father{
    private String name = "atguigu";  //private 只能在本类中使用。
    int age = 0;
}

 this、继承时构造器的调用

public class Teacher extends Person{
    private String name = "tom";
    public Teacher(){
        System.out.println("this is a teacher.");
//        super(); //编译错误,必须在子类构造器的首行
    }
    public static void main(String[] args){
        Teacher tea = new Teacher();
//        System.out.println(this.name);//编译错误,this不能在static方法中使用的
    }
}
class Person{
    public Person(){
        System.out.println("this is a Person.");
    }
}

继承、构造器、super、方法的重写、多态引用

public class Test {

    public static void main(String[] args) {
        Base b1 = new Base();//本态引用,只看Base类,执行了Base类的无参构造,在无参构造中,调用了Base类的method(100)
        Base b2 = new Sub();  //执行的是子类重写的方法。
        //多态引用,创建的是子类的对象,执行子类Sub的无参构造;
//在子类的构造器中,一定会调用父类的构造器,默认调用的是父类的无参构造,会导致父类的无参构造被执行,因为父类的无参构造中调用method(100),
//它省略了“this.”,这个this是当前对象,当前正在创建的是子类Sub的对象,执行的是子类Sub重写的method(100) 
//接着在子类的构造器中,有super.method(70),这个执行的是父类的method(70),所以会打印 Base:70
    
    }
}
class Base{
    Base(){
        method(100); //省略了this.method(100),this指当前对象
    }
    public void method(int i){
        System.out.println("base : " + i);  // 1.base: 100;  3. base: 70
    }
}
class Sub extends Base{
    Sub(){
              //省略了super();
        super.method(70);  //super.方法。子类重写了method方法,但是它又想调用父类的method方法了。
    }
    public void method(int j){  //子类重写了method方法。
        System.out.println("sub : " + j); //2.  sub: 100 ;
    }
}

--->>
base : 100
sub : 100
base : 70

 类初始化和实例初始化

如果没有实例化(例如main方法中执行了某个函数),没有创建对象,只执行类的实例化,不进行实例的初始化。

public class Test {
    {
        System.out.println("b");
    }
    static{
        System.out.println("a");
    }
    Test(){
        System.out.println("c");
    }
    public static String getOut(){
        try {
            return "1";
        } catch (Exception e) {
            return "2";
        }finally{
            return "3";
        }
    }
    public static void main(String[] args) {
        System.out.println(getOut());
    }
}

===》》 a  3
View Code
* 类初始化和实例初始化
* (1)先类初始化
*   A:如果父类没有初始化,会先初始化父类
*   B:类的初始化执行的是<clinit>方法,它由两部分组成:
*     (a)静态变量的显式赋值语句  (b)静态代码块的语句,(a)(b)谁在上谁先执行
* 
* (2)实例初始化
*   A:创建子类对象时,也会导致父类的实例初始化方法执行
*   B:每一个构造器都会有对应的实例初始化方法
*   C:每一个实例初始化有三部分组成:
*     (a)非静态变量的显示初始化代码(b)非静态代码块的语句(c)构造器;  (a)(b)谁在上谁先执行,构造器后执行

 子类继承父类,子类和父类都有无参构造和有参构造;子类在进行创建对象时,不管子类创建对象时候它有没有传参,

子类都是默认调用父类的无参构造,如果传参了,那么参数传给的是子类的有参构造。

练习:

/*
 * 实例初始化的过程:
 * 1、父类的实例初始化<init>()
 *      因为子类默认调用父类的无参构造,那么选择父类的<init>(),而不是<init>(String name)
 *         System.out.print("1");
 * 2、子类的实例初始化
 *         System.out.print("3");
 *         father = new People(name +" F"); //创建了父类的对象
 *             这句代码会导致,父类的有参构造,即父类的<init>(String name)会执行
 *                 System.out.print("2");
 *         
 */
public class TestChild {
    public static void main(String[] args) {
        new Child("mike");//
    }
}
class People{
    private String name;
    public People(){
        System.out.print("1");
    }

    public People(String name){
        System.out.print("2");
        this.name = name;
        System.out.println(name);
    }
}
class Child extends People{
    People father;
    
    //子类的构造器中,默认会调用父类的无参构造
    public Child(String name){
        System.out.print("3");
        father = new People(name +" F");
        
    }
    
    public Child(){
        System.out.print("4");
    }

}

打印:--->>
132mike F
View Code

父类初始化< clinit >---->>>子类初始化< clinit >--->>  父类的实例初始化< init > --->>子类的实例初始化< init >;一开始都是静态的先初始化。

(1.先父类初始化;2.子类初始化; 3.父类实例初始化; 4.子类实例初始化。)

练习:

* 1、实例初始化,为属性赋值的过程
 *     (1)父类的实例初始化方法<init>()
 *             x = 10;//父类中的x
 *             this.print();//要考虑方法的重写,因为在创建子类Son的对象,所以这个this是子类的对象
 *                     System.out.println("Son.x = " + x);// Son.x = 0  ,这个是子类中的x
 *             x = 20;//父类中的x
 *     (2)子类的实例初始化方法<init>()
 *             x = 30;//子类的x
 *             this.print();
 *                     System.out.println("Son.x = " + x);//子类中的x,就近原则    Son.x = 30
            x = 40;//子类的x
 *             
 * 2、属性没有多态
 *             System.out.println(f.x);//按照编译时类型,父类的x
 */
public class Exam3 {
    public static void main(String[] args) {
        Father f = new Son();
        System.out.println(f.x);//先初始化最后执行这个,按照编译时类型,父类的x;属性没有多态。
    }
}
class Father{
    int x = 10;      //父类的实例初始化; 显式赋值;
    public Father(){ //构造器;
        this.print();//this指的是当前对象,即Son对象,它重写了print方法,所以调用的是子类的print方法
        x = 20;
    }
    public void print(){
        System.out.println("Father.x = " + x);
    }
}
class Son extends Father{
    int x = 30;
    public Son(){
        this.print();
        x = 40;
    }
    public void print(){                   //执行这个方法的时候x还没赋值,它的默认值为0
        System.out.println("Son.x = " + x);//子类中的x,就近原则  
    }
}

----->>> 打印:

  Son.x = 0
  Son.x = 30
  20

* 实例初始化的问题:
 * 1、创建父类对象时
 *     执行父类的实例初始化方法<init>
 *         System.out.println("father create");
 * 2、创建子类对象时
 *     执行父类的实例初始化方法<init>
 *         System.out.println("father create");
 *  执行子类的实例初始化方法<init>
 *      System.out.println("child create");
 */
public class Child extends Father{
    public Child(){
        System.out.println("child create");
    }
    
    public static void main(String[] args) {
        Father f = new Father();   //先执行这一句,父类 f 的实例初始化 
        Child c = new Child();    //再执行子类的实例初始化 --> 它会导致父类的先初始化再初始化子类
    }
}

public class Father {
    public Father(){
        System.out.println("father create");
    }
}

打印:
father create
father create
child create
 * 1、创建对象
 *     实例初始化
 * (1)父类的实例初始化<init>
 *         name = "father"; //这个name是父类的name
 * (2)子类的实例初始化<init>
 *         name = "test"; //这个name是子类的name
 * 
 * 2、对象调用方法
 *     调用的是子类从父类继承的getName()
 * 
 * 子类的对象有两个name,   this.name,如果在子类中,this.name就是子类的,如果在父类中,this.name就是父类的
 */
public class Test extends Father{
    private String name = "test";
    
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.getName());
    }
}

public class Father {
    private String name = "father";

    public String getName() {
        return name;//这里就近原则,找的是父类的name
    }
}
 * 1、创建对象
 *         Other o = new Other(); o.i = 0;
 * 2、调用了addOne(o)
 *         o.i++;        o.i = 1;
 * 3、final修饰的变量不可变问题
 *     是修饰什么变量,局部变量还是成员变量?
 */
public class Something {
    public static void main(String[] args) {
        Other o = new Other();
        new Something().addOne(o); //对象.方法
        System.out.println(o.i);
    }    
    //final修饰的变量不可变;  这里是o变量不可变
    public void addOne(final Other o){
//        o = new Other();//o的变量值不可变
        o.i++;
    }
}
class Other{
    public int i;
}
 * 1、static
 *      本类中,静态的方法,代码块可以访问静态的属性
 * 2、类初始化
 *     main方法所在的类必须先初始化,然后才能执行main方法
 *    
 *    Myclass2类的初始化<clinit>()
 *        static{
            int x = 5;
            x--;//这里的x是局部变量的x,不是类变量的x  x = 4
        }
        static{
            x--;//这里的x是类变量的x  x = -1
        }
 * 在执行main
 *         System.out.println("x = " + x);//类变量的x   x=-1
        z--;//类变量的z   z= -1
        myMethod();
            y = z++ + ++z;//都是类变量
            (1)先把z=-1的值load到操作数栈(2)z++,z=0(3)++z,z=1(4)再把z=1的值load到操作数栈(5)计算-1+1(6)赋值给y=0
        System.out.println("result: " + (z + y + ++z));
            (1)先把z=1的值load到操作数栈(2)再把y=0的值load到操作数栈
            (3)++z,z=2(4)先把z=2的值load到操作数栈(5)执行1+0+2(6)打印3
 * 2、局部变量与成员变量(类变量、实例变量)
 * 3、自增问题
 * 
 */
public class Myclass2 {
    static int x,y,z;
    static{
        int x = 5;  //局部变量
        x--;
    }
    static{
        x--;  //这里的x是类变量
    }
    public static void main(String[] args) {
        System.out.println("x = " + x);//类变量的x   x=-1
        z--;//类变量的z   z= -1
        myMethod();
        System.out.println("result: " + (z + y + ++z));
    }
    
    public static void myMethod(){
        y = z++ + ++z;
    }
}

x = -1
result: 3
==和equals()的区别

==:如果是基本数据类型,比较的是数据值
如果是引用数据类型,比较的是对象的地址值
equals():必须是对象才能调用,它是Object类中声明的,如果子类没有重写,那么它的效果和==是一样的,也是比较对象的地址。如果子类重写了,
那么就按照重写的规则进行比较,例如String类型重写了equals,比较的是字符串的字符内容。

重写一个类的equals方法需要主意什么?

(1)必须和hashCode()方法一起重写,凡是参与equals比较的属性,一定要参与hashCode值的计算。
(2)equals的重写要求遵循几个原则:
equals 方法在非空对象引用上实现相等关系: 
•    自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。 
•    对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。 
•    传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。 
•    一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。 
•    对于任何非空引用值 x,x.equals(null) 都应返回 false
原文地址:https://www.cnblogs.com/shengyang17/p/10004038.html