面向对象的进阶

194 阅读9分钟

面向对象的进阶

1.类变量

 // 类变量:叫做静态变量/静态属性 ,是该类所有的对象共享的变量,任何一个该类的对象去访问它得到的都是相同的值

        // 定义语法: 访问修饰符 + static + 数据类型 + 变量名

        //如何访问  1.类名.变量名 (最好用这个,比较规范)    // 在类加载的时候  静态变量就已经被加载好了
        //         2.对象名.变量名


// 使用细节
        //1.当一个类中所有对象共享一个变量的时候,使用静态变量
        //2.加上static是静态变量 不加是实例变量/普同变量/非静态变量
        //3.做静态变量/静态属性 ,是该类所有的对象共享的变量,实例变量是每个对象独享的
        //4.//如何访问  1.类名.变量名
        //            2.对象名.变量名
        //5.实例变量不能通过类名.变量名去访问   需要创建对象 对象名.变量名
        //6.在类加载的时候  静态变量就已经被加载好了,即使不创建对象,只要类加载就可以使用类变量
        //7.类的生命周期是随类的加载开始,随类消亡

// 内存分析
        //1.在栈中 生成child1 -> 指向 堆中的地址 就是该对象的地址 之后在指向方法区 获取信息
        //2.同时共享堆中的静态变量

//实例讲解
 Child child1 = new Child("奶盖");
        child1.join();
     //   count++;
        Child child2 = new Child("酷盖");
        child2.join();
       // count++;
        Child child3 = new Child("盖");
        child3.join();
       // count++;
       System.out.println("共有" + Child.count);
class Child{
    private String name;
    public static int count = 0;  //该变量最大的特点是会被Child的所有对像实现共享

    //1.static 同一个类的所有对象共享
    //2.static 在类加载的时候就加载好了

    public Child() {
    }

    public Child(String name) {
        this.name = name;
    }
    public void join(){
        count++;
        System.out.println(name + " 加入");

    }

2.类方法

 // 类方法
    // 语法: 访问修饰符 + static + 数据返回类型 方法名(){}
    // 调用: 类名。类方法名   或者 对象名。类方法名

    // 好处 方便调用

    // 使用细节
    //1.类方法和普通方法都是随类的加载而加载,将结构信息存储到方法区里面 类方法无this的参数 普通方法中隐含着this的参数
    //2.调用: 类名。类方法名   或者 对象名。类方法名
    //3.类方法中不允许使用和对象有关的关键字 this super   普通方法可以
    //4.(重点) 静态方法只能访问静态变量和静态方法  普通方法既可以访问静态变量 静态方法 也可以访问普通变量 普通方法NM

3.代码块

        // 代码块
        //好处
        //1.相当于另外一种形式的构造器(对构造器的补充机制) 可以进行初始化操作
        //2.场景 多个构造器都有重复语句,可以抽取到初始代码块中,提高代码重复性


        //使用细节
        //1.static代码块 ,作用对类进行初始化 ,随类的加载而执行,并且只能执行一次,每创建一个对象就执行一次

        //2.类在什么时候加载  重点
        1).创建对象实例时,(new)
        2).创建子类对象实例,父类也会被加载 // 会调用父类的构造器
        3).使用类的静态成员时,(静态属性 静态方法)
            
        //3.普通代码块只有创建新的对象才会被调用


 	   //4. 创建一个对象时,在一个类的调用顺序  重点 难点
        1)调用静态代码块和静态属性初始化
            (静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和静态属性初始化按顺序调用)
       2)调用普通代码块和普通属性初始化
            (普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和普通属性初始化按顺序调用)
        3)调用构造方法(如果有父类,会先执行父类的普通代码块 构造器 在执行子类的普通代码块 构造器)

        //5.构造器的前面隐含了super() 和 调用普通代码块   但是父类优先于子类
    //6.创建子类的对象时(继承关系) 静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法使用顺序
        1.父类的 静态代码块,静态属性初始化(优先级一样,按定义的顺序)
        2.子类的 静态代码块,静态属性初始化(优先级一样,按定义的顺序)
        3..父类的 普通代码块,普通属性初始化(优先级一样,按定义的顺序)
        4.父类的构造方法
        5.子类的 普通代码块,普通属性初始化(优先级一样,按定义的顺序)
        6.子类的构造方法
//代码块调用顺序的实例讲解
class teacher{

    {
        System.out.println("父类的普通代码块");  //5.
    }

   public static int n1 = getN1();     

    public teacher() {
        System.out.println("父类的无参构造器");     //6.
    }

    static {
       System.out.println("父类的静态属性代码块"); //2.
   }
    public static int getN1(){
       System.out.println("老师教学的静态方法");  //1.
       return 100;
    }

}

class Stu extends teacher{
    public Stu() {
        System.out.println("子类的无参构造器");  //8.
    }

    public Stu(String name) {
        System.out.println("子类的有参构造器");
    }

    {
        System.out.println("子类的普通代码块"); //7.
    }
    private static int n2 = s();
    static {
        System.out.println("子类的静态代码块");  //4.
    }
    public static int s(){
        System.out.println("学生的静态学习方法"); //3.
        return 2;
    }

    public int s1(){
        System.out.println("学生的普通方法");
        return 1;
    }


}
 // final的使用细节
        //1.final修饰的属性也叫常量  一般 XX XX XX_XX 定义
        //2.final修饰的属性在定义的时候,必须赋初始值  赋值的位置有

        //1)定义的时候
        //2)构造器中
        //3)代码块中

        //3.finaL修饰的属性如果是静态的,则初始化的地方只能是 定义时,在静态代码块 可以,构造器里面不能赋值
        //4. final类不能继承,但可以实例化对象
        //5.如果类不是final类,但是含有final 的方法 ,虽然不能重写但是可以继承
        //6.如果一个类已经是final类,就没有必要再将方法修饰成final方法了
        //7.final不能修饰构造器
        //8.final 和static 往往搭配使用,效率更高 ,不会导致类的加载(进而 不会调用静态代码块)—,底层编译器做了优化处理
        //9.包装类 String Boolean不能被继承

4.接口

// 接口介绍 :对一些不明确的方法进行封装到一起,之后在类中重写接口的方法
    就是给出一些没有实现的方法,封装到一起,到某个类使用的时候,根据具体情况把方法写出来

    //  interface 接口名{  属性      方法}

    // class 类名 implement 接口 {自己的属性  自己的方法  必须实现的接口的抽象方法}

     //接口的使用细节
    //1.接口不能实例化
    //2.接口中的方法是 public 方法 接口中的抽象方法不用抽象修饰符修饰
    //3.一个普通类实现接口,就必须将接口的所有方法实现
    //4.抽象类实现接口,可以不用实现接口的方法
        
     //5.一个类可以同时访问多个接口
     //6.接口的属性只能是final 而且是public static final 修饰的 int a = 1; ==  public static final;
     //7.接口的访问形式  接口名.属性名
     //8.接口不能继承其他类,但是可以继承多个接口  interface A extends B,C{}
     //9.接口的修饰符只能是 public 和默认  这点和类的修饰符一样



        
        
        
// 好处: 便于统一管理  统一方法名 便于调用   对继承的继承模式的补充
// 接口 Vs 继承like
//1.接口更加灵活,继承必须满足is-a的关系 like-a的关系
        // 接口 VS 继承类
    //  继承的价值主要在于: 解决代码的复用性和可维护性
    //  接口的价值体现在: 设计,设计好各种规范(方法),让其它类实现这些方法,即更加灵活

    // 接口比继承更加灵活
    // 继承需要满足 is -a的关系  接口只需要满足like-a的关系
    // 接口在一定情况再实现了代码的解耦(接口规范性 +动态绑定)

 // 接口多态传递

    IG ig = new N();
    IH ih = new N();

    //如果IG继承了IH的接口,而N类实现了对IG的接口  那么也就说明N 也玩成了IH的接口  这就是接口的多态传递
}
interface IH{

}
interface IG extends IH{

}
class N implements IG{

}
// 目前 类的五大成员已完成 成员方法 成员变量 构造器 代码块  还有内部类没学
//接口的实例讲解

    public static void main(String [] args){

        littleMonkey littleMonkey = new littleMonkey("齐天大圣");
       littleMonkey.climb();
       littleMonkey.swim();
       littleMonkey.fly();


    }
}
class Monkey{
    private String name;

    public Monkey() {
    }

    public Monkey(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void climb(){
        System.out.println( name + "会爬树");
    }
}
interface FishAbility{
    public void swim();
}
interface BirdAbility{
    public void fly();
}
class littleMonkey extends Monkey implements FishAbility,BirdAbility{

    public littleMonkey() {
    }

    public littleMonkey(String name) {
        super(name);
    }

    @Override
    public void climb() {
        super.climb();
    }

    @Override
    public void swim() {
        System.out.println(getName()+"会游泳");
    }

    @Override
    public void fly() {
        System.out.println(getName() + "会上天");
    }
}



5.抽象类

// 抽象类
        //当父类的某些方法不确定的时候,用abstract来修饰
        // 使用方法
        //1.抽象方法就是没有实现的方法
        //2.所以抽象方法没有方法体
        //3.当一个类中存在抽象方法,该类要声明为抽象类
        //4.一般,抽象类会被继承,由子类完成抽象方法



        // 使用细节
        //1.抽象类不能实例化
       // A a = new A();  1.抽象类不能实例化
        //2.抽象类 不一定需要包含Abstract方法
        //3.一旦类中有抽象方法,类必须修饰为抽象类
        //4.Abstract不能修饰属性和其他 只能修饰类和方法
        //5.抽象类可以有任何成员(本质还是类) 如 非抽象方法 构造器 静态属性 静态方法
        //6.抽象方法不能有主体
        //7.如果一个类继承了抽象类必须实现抽象类的抽象方法,除非他也声明为抽象类
        //8.抽象方法不能使用private final static 因为这些关键字和重写违背


实例讲解
    / 抽象类的模板设计模式

//提高了代码复用性
public class AbstractHomeWork01 {
    public static void main(String [] args){
        cal cal = new cal();
        cal.time();


    }
}
abstract class Template{

    public abstract void job();

    public void time(){
        long start = System.currentTimeMillis();  //二  得到当前的时间

        job();

        long end = System.currentTimeMillis();
        System.out.println("执行的时间"  + (end - start) );

    }



}
class cal extends Template{

//    public void Time(){
//        long start = System.currentTimeMillis();  //二  得到当前的时间
//
//        job();
//
//        long end = System.currentTimeMillis();
//        System.out.println("执行的时间"  + (end - start) );
//
//    }
    public void job(){
//        long start = System.currentTimeMillis();  //一  得到当前的时间
        long num = 0;
        for (long  i = 0; i < 88800000; i++) {
            num += i;
        }
//        long end = System.currentTimeMillis();
//        System.out.println("执行的时间"  + (end - start) +" " + "i =" + num);

    }

}