1. 类和对象的内存分配机制

 
 
1.1 分配机制
 Java 内存的结构分析
- 栈: 一般存放基本数据类型(局部变量)
- 堆: 存放对象(Cat cat , 数组等)
- 方法区:常量池(常量,比如字符串), 类加载信息
- 示意图 [Cat (name, age, price)]
  Java 创建对象的流程简单分析
Person p = new Person();
p.name = “jack”;
p.age = 10
说明:
- 先加载 Person 类信息(属性和方法信息, 只会加载一次)
- 在堆中分配空间, 进行默认初始化(看规则)
- 把地址赋给 p , p 就指向对象
- 进行指定初始化, 比如 p.name =”jack” p.age = 10
2. 继承
2.1 super、this只能使用在构造方法中
super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
class Student{
    public Student(){
		
    }
    public Student(int a){
        this(); // 可以 调用无参构造
    }
    public void create(){
        //super(); //错误,super只能在构造方法中调用
    }
}
2.2 继承内存机制

package com.hspedu.extend_;
/**
 * 讲解继承的本质
 */
public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();//内存的布局
        //?-> 这时请大家注意,要按照查找关系来返回信息
        //(1) 首先看子类是否有该属性
        //(2) 如果子类有这个属性,并且可以访问,则返回信息
        //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
        System.out.println(son.name);//返回就是大头儿子
        //System.out.println(son.age);//返回的就是39
        //System.out.println(son.getAge());//返回的就是39
        System.out.println(son.hobby);//返回的就是旅游
    }
}
class GrandPa { //爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}
class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;
    public int getAge() {
        return age;
    }
}
class Son extends Father { //子类
    String name = "大头儿子";
}
补充:
如果一个类的上一级父类有一个属性被private修饰,那么将无法访问该资源,即使这个类的爷爷类有也不能访问
2.3 重写和重载的区别

2.4 this 和 super的区别

3. 多态
3.1 细节补充

属性没有重写之说!属性的值看编译类型
3.2 动态绑定机制

package com.hspedu.poly_.dynamic_;
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//?40 -> 30
        System.out.println(a.sum1());//?30-> 20
    }
}
class A {//父类
    public int i = 10;
    //动态绑定机制:
    public int sum() {//父类sum()
        return getI() + 10;//20 + 10
    }
    public int sum1() {//父类sum1()
        return i + 10;//10 + 10
    }
    public int getI() {//父类getI
        return i;
    }
}
class B extends A {//子类
    public int i = 20;
//    public int sum() {
//        return i + 20;
//    }
    public int getI() {//子类getI()
        return i;
    }
//    public int sum1() {
//        return i + 10;
//    }
}
4. Object
4.1 equals方法

package com.hspedu.object_;
public class Equals01 {
    public static void main(String[] args) {
        A a = new A();
        A b = a;
        A c = b;
        System.out.println(a == c);//true
        System.out.println(b == c);//true
        B bObj = a;
        System.out.println(bObj == c);//true
        int num1 = 10;
        double num2 = 10.0;
        System.out.println(num1 == num2);//基本数据类型,判断值是否相等
        //equals 方法,源码怎么查看.
        //把光标放在equals方法,直接输入ctrl+b
        //如果你使用不了. 自己配置. 即可使用.
        /*
        //带大家看看Jdk的源码 String类的 equals方法
        //把Object的equals方法重写了,变成了比较两个字符串值是否相同
        public boolean equals(Object anObject) {
        if (this == anObject) {//如果是同一个对象
            return true;//返回true
        }
        if (anObject instanceof String) {//判断类型
            String anotherString = (String)anObject;//向下转型
            int n = value.length;
            if (n == anotherString.value.length) {//如果长度相同
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {//然后一个一个的比较字符
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;//如果两个字符串的所有字符都相等,则返回true
            }
        }
        return false;//如果比较的不是字符串,则直接返回false
    }
         */
        "hello".equals("abc");
        //看看Object类的 equals 是
        /*
        //即Object 的equals 方法默认就是比较对象地址是否相同
        //也就是判断两个对象是不是同一个对象.
         public boolean equals(Object obj) {
            return (this == obj);
        }
         */
        /*
        //从源码可以看到 Integer 也重写了Object的equals方法,
        //变成了判断两个值是否相同
        public boolean equals(Object obj) {
            if (obj instanceof Integer) {
                return value == ((Integer)obj).intValue();
            }
            return false;
        }
         */
        Integer integer1 = new Integer(1000);
        Integer integer2 = new Integer(1000);
        System.out.println(integer1 == integer2);//false
        System.out.println(integer1.equals(integer2));//true
        String str1 = new String("hspedu");
        String str2 = new String("hspedu");
        System.out.println(str1 == str2);//false
        System.out.println(str1.equals(str2));//true
    }
}
class B {}
class A extends B {}
4.2 finalize 方法
- 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作
- 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来
 销毁该对象,在销毁该对象前,会先调用 finalize 方法。
- 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制
5. 静态方法(类方法)细节

package com.hspedu.static_;
public class StaticMethodDetail {
    public static void main(String[] args) {
        D.hi();//ok
        //非静态方法,不能通过类名调用
        //D.say();, 错误,需要先创建对象,再调用
        new D().say();//可以
    }
}
class D {
    private int n1 = 100;
    private static  int n2 = 200;
    public void say() {//非静态方法,普通方法
    }
    public static  void hi() {//静态方法,类方法
        //类方法中不允许使用和对象有关的关键字,
        //比如this和super。普通方法(成员方法)可以。
        //System.out.println(this.n1);
    }
    //类方法(静态方法)中 只能访问 静态变量 或静态方法
    //口诀:静态方法只能访问静态成员.
    public static void hello() {
        System.out.println(n2);
        System.out.println(D.n2);
        //System.out.println(this.n2);不能使用
        hi();//OK
        //say();//错误
    }
    //普通成员方法,既可以访问  非静态成员,也可以访问静态成员
    //小结: 非静态方法可以访问 静态成员和非静态成员
    public void ok() {
        //非静态成员
        System.out.println(n1);
        say();
        //静态成员
        System.out.println(n2);
        hello();
    }
}
5.1 构造方法可以调用静态和非静态资源
class Person {
    private int id;
    private static int total = 0;
    public static int getTotalPerson() {
        //id++;//错误, 注销
        return total;
    }
    public Person() {//构造器
        total++;  //total = 1
        id = total;//id = 1
    }
}
class TestPerson {
    public static void main(String[] args) {
        System.out.println("Number of total is " +Person.getTotalPerson()); //0
        Person p1 = new Person();
        System.out.println( "Number of total is "+ Person.getTotalPerson()); //1
    }
}
5.2 static修饰的方法不可以使用this/super等关键字
class Person { 
    private int id;
    private static int total = 0;
    public static void setTotalPerson(int total){
        // this.total = total;//错误,因为在static方法中,不可以使用this 关键字
        Person.total = total;
    }
    public Person() {//构造器
        total++;
        id = total;
    }
    //编写一个方法,输出total的值
    public static void m() {
        System.out.println("total的值=" + total);
    }
}
class TestPerson {
    public static void main(String[] args) {
        Person.setTotalPerson(3);
        new Person(); //最后 total的值就是4
        Person.m();//看看输出的是不是4
    }
}
小结:
记住两句话
(1) 静态方法,只能访问静态成员
(2) 非静态方法,可以访问所有的成员
(3) 在编写代码时,仍然要遵守访问权限规则
5. 代码块
5.1 细节补充

package com.hspedu.codeblock_;
public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //1. 创建对象实例时(new)
        // AA aa = new AA();
        //2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载
        // AA aa2 = new AA();
        //3. 使用类的静态成员时(静态属性,静态方法)
        // System.out.println(Cat.n1);
        //static代码块,是在类加载时,执行的,而且只会执行一次.
//        DD dd = new DD();
//        DD dd1 = new DD();
        //普通的代码块,在创建对象实例时,会被隐式的调用。
        // 被创建一次,就会调用一次。
        // 如果只是使用类的静态成员时,普通代码块并不会执行
        System.out.println(DD.n1);//8888, 静态模块块一定会执行
    }
}
class DD {
    public static int n1 = 8888;//静态属性
    //静态代码块
    static {
        System.out.println("DD 的静态代码1被执行...");//
    }
    //普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
    //可以这样简单的,理解 普通代码块是构造器的补充
    {
        System.out.println("DD 的普通代码块...");
    }
}
class Animal {
    //静态代码块
    static {
        System.out.println("Animal 的静态代码1被执行...");//
    }
}
class Cat extends Animal {
    public static  int n1 = 999;//静态属性
    //静态代码块
    static {
        System.out.println("Cat 的静态代码1被执行...");//
    }
}
class BB {
    //静态代码块
    static {
        System.out.println("BB 的静态代码1被执行...");//1
    }
}
class AA extends BB {
    //静态代码块
    static {
        System.out.println("AA 的静态代码1被执行...");//2
    }
}

5.2 静态代码块只能调用静态成员
6. 各方法代码块之间的执行顺序

package com.hspedu.codeblock_;
public class CodeBlockDetail04 {
    public static void main(String[] args) {
        //老师说明
        //(1) 进行类的加载
        //1.1 先加载 父类 A02 1.2 再加载 B02
        //(2) 创建对象
        //2.1 从子类的构造器开始
        //new B02();//对象
        new C02();
    }
}
class A02 { //父类
    private static int n1 = getVal01();
    static {
        System.out.println("A02的一个静态代码块..");//(2)
    }
    {
        System.out.println("A02的第一个普通代码块..");//(5)
    }
    public int n3 = getVal02();//普通属性的初始化
    public static int getVal01() {
        System.out.println("getVal01");//(1)
        return 10;
    }
    public int getVal02() {
        System.out.println("getVal02");//(6)
        return 10;
    }
    public A02() {//构造器
        //隐藏
        //super()
        //普通代码和普通属性的初始化......
        System.out.println("A02的构造器");//(7)
    }
}
class C02 {
    private int n1 = 100;
    private static  int n2 = 200;
    private void m1() {
    }
    private static void m2() {
    }
    static {
        //静态代码块,只能调用静态成员
        //System.out.println(n1);错误
        System.out.println(n2);//ok
        //m1();//错误
        m2();
    }
    {
        //普通代码块,可以使用任意成员
        System.out.println(n1);
        System.out.println(n2);//ok
        m1();
        m2();
    }
}
class B02 extends A02 { //
    private static int n3 = getVal03();
    static {
        System.out.println("B02的一个静态代码块..");//(4)
    }
    public int n5 = getVal04();
    {
        System.out.println("B02的第一个普通代码块..");//(9)
    }
    public static int getVal03() {
        System.out.println("getVal03");//(3)
        return 10;
    }
    public int getVal04() {
        System.out.println("getVal04");//(8)
        return 10;
    }
    //一定要慢慢的去品..
    public B02() {//构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("B02的构造器");//(10)
        // TODO Auto-generated constructor stub
    }
}
7. final细节补充
7.1 final的修饰属性的赋值

package com.hspedu.final_;
public class FinalDetail01 {
    public static void main(String[] args) {
        CC cc = new CC();
        new EE().cal();
    }
}
class AA {
    /*
    1. 定义时:如 public final double TAX_RATE=0.08;
    2. 在构造器中
    3. 在代码块中
     */
    public final double TAX_RATE = 0.08;//1.定义时赋值
    public final double TAX_RATE2 ;
    public final double TAX_RATE3 ;
    public AA() {//构造器中赋值
        TAX_RATE2 = 1.1;
    }
    {//在代码块赋值
        TAX_RATE3 = 8.8;
    }
}
class BB {
    /*
    如果final修饰的属性是静态的,则初始化的位置只能是
    1 定义时  2 在静态代码块 不能在构造器中赋值。
     */
    public static final double TAX_RATE = 99.9;
    public static final double TAX_RATE2 ;
    static {
        TAX_RATE2 = 3.3;
    }
}
//final类不能继承,但是可以实例化对象
final class CC { }
//如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
//即,仍然遵守继承的机制.
class DD {
    public final void cal() {
        System.out.println("cal()方法");
    }
}
class EE extends DD { }
7.1 权限修饰符和static修饰的常量不会导致类加载

package com.hspedu.final_;
public class FinalDetail02 {
    public static void main(String[] args) {
        System.out.println(BBB.num); //10000
        //不会执行静态代码块,因为final和static修饰的常量不会导致类加载
        //包装类,String 是final类,不能被继承
    }
}
//final 和 static 往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理
class BBB {
    public final static  int num = 10000;
    static {
        System.out.println("BBB 静态代码块被执行");
    }
}
final class AAA{
    //一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法
    //public final void cry() {}
}



















