test页首

java面向对象


成员 = 属性 + 方法

类和对象内存分配机制

  1. 栈:基本数据类型
  2. 堆:对象(数组)
  3. 方法区:常量池(如字符串),类加载信息
  4. Person p = new Person();
    1. 加载Person类信息(属性和方法信息,只会加载一次
    2. 堆中分配空间,默认初始化
    3. 堆地址赋给p

构造器

构造方法可以处于public、protected、private和默认四种访问级别之一
没有定义构造器,系统自动默认构造方法如Person(){}
一但用户定义,默认构造器就被覆盖了,还想用无参构造器要显式定义

访问修饰符:

4种修饰符来修饰类属性和类方法。修饰类只有默认和public

级别 修饰符 同类 同包 子类 不同包
公开 public 1 1 1 1
保护 protected 1 1 1 0
默认 1 1 0 0
私有 private 1 0 0 0

封装

私有 get set,set中可以进行安全性检查

继承

extends还有依赖组合聚合

  • 子类继承父类方法变量(一般要继承的方法写成public,变量才写私有的)
  • 所有类都默认继承Object类(java.lang.Object)(有equals,hashcode等方法)
  • java类只能单继承 A->B->C 不能A->B,C
  • 子类每个构造器都会默认调用父类无参构造器,可以显式更改super(1),super只能放第一行

多态

1、类型转换

子类重写父类方法,父类引用指向子类对象

  1. 方法名,参数列表必须相同,返回类型只能缩小不能扩大
  2. 修饰符可以扩大不能缩写 public>protected>default>private
  3. 抛出的异常可以缩小不能扩大,
Person p = new Student();	//父类的引用可以指向子类的实现  
p.test();  			//im a student,子类重写了父类方法就掉用子类的  
p.exam();			//报错 父类没有exam方法, 
//编译类型Person ,运行类型Student
Animal[] a =new Animal[3];
a[0]=new Animal();
a[1]=new Kitten();
a[2]=new Puppy();
for (int i = 0; i < 3; i++) 
    show(a)

2、多态参数

形参父类,实参子类

void show(Animal a){
    a.say()
    if(a instanceof Kitten)
        ...
}

3、动态绑定机制

当调用对象方法时,该方法会和该对象内存地址(运行类型)绑定。属性则不会。

A extends B  
A:int i=10; geti();sum(){return geti()+1}  
B:int i=20; geti();sum(){return geti()+1}  
B b=new A()
b.sum()//11
A extends B  
A:int i=10; geti();sum(){return i+1}  
B:int i=20; geti();sum(){return i+1}  
B b=new A()
b.sum()//21

总结:

1、编译类型,运行类型,调方法顺运行类型向上查找。
2、强转只能转父类引用(而非对象),它必须指向的是要转的类型。否则ClassCastException
3、属性没有重写,只看编译类型
4、a instanceof B 判断a的运行类型是不是B的子类型 A extends B , A a = new B() a instanceof B :true

static静态成员

public static int count = 0;
public static int sum(int a,int b);

  • 访问规则同非静态的,各实例共享,没有实例也能访问。推荐用类名访问
  • 静态方法只能访问静态成员,不能使用this
    非静态方法可以访问静态成员
  • 静态方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区
  • jdk8以前存放在方法区静态域,jdk8后放在堆,跟反射机制有关
  • 不涉及实例的成员时可以设计成静态方法提高效率

final

可修饰类,类成员,局部变量
final类不可被继承,final方法不可被子类重写,final属性,final局部变量不可修改

  • final 属性在定义时(可在定义时,代码块,构造器中)赋值,之后不能再修改。

    final变量定义的时候,可以先声明,而不给初值。这样final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。提供了更大的灵活性

  • 如果是final static属性,只能在定义时,静态代码块中赋值
  • final类方法就可以不用写final了,因为没有子类重写。(final类中的方法默认是final的。)
  • final不能修饰构造方法,因为构造函数不是继承而来的
  • final static搭配效率更高,编译器做了优化,调用时不会导致类加载
  • 注意final 对象(修饰了引用)
        public void change(final int a) {
            a++;//报错
        }
        public void change(final A a) {
            a.i=5;//ok
            a = new A();//改变了a的值,报错
        }
    

abstract抽象类

abstract只修饰类和方法
public abstract void eat(); //没有方法体

  • 父类方法不确定时,只需声明不用实现。留给子类重写。有抽象方法必须声明为抽象类
  • 抽象类不能实例化
  • 抽象类不一定要有抽象方法
  • 子类继承了抽象类,必须实现抽象类所有的抽象方法,除非它自己声明为抽象类。
  • 抽象方法不能用private,final,static修饰

    static可以被类直接调用,抽象方法没有方法体,矛盾

代码块(初始化块)

类什么时候会被加载

  1. 创建对象实例时(new)
  2. 创建子类对象实例,父类也会被加载
  3. 使用类的静态成员时
//只在加载类或者创建对象时被隐式调用
[修饰符]{//修饰符只能为static(静态代码块)或空(普通代码块)
    代码
};
//相当于另一种形式的构造器。多个构造器的重复语句可以抽取到代码块中
  • static代码块:类加载时执行且只执行一次
  • 普通代码块:每创建一个对象都执行一次
  • 静态代码块只能调用静态成员,普通代码块可以调用任意成员
  • 只使用类的静态成员时,普通代码块并不会执行
  • 不管调用哪个构造器都会先执行代码块,构造器隐含了super()和普通代码块
    public A(){
        //super()
        //普通代码块
        do something
    }
    
  • 代码块优先于构造器
  • 掉用子类的static变量时也会加载父类代码块

执行顺序

创建一个对象时,一个类的调用顺序:

  1. 父类静态代码块和静态属性初始化(两者优先级一样,看定义顺序)
  2. 子类静态代码块和静态属性初始化(同优先级)
  3. 父类普通代码块和普通属性初始化(同优先级)
  4. 父类构造方法
  5. 子类普通代码块和普通属性初始化(同优先级)
  6. 子类构造方法

接口

public interface USB{
    public void start();//规定接口方法
}
public class Phone implements USB{
    public void start(){
        sout('convert file...');//实现接口方法
    }
}
public class Camera implements USB{
    public void start(){
        sout('convert photo...');//实现接口方法
    }
}
public class Computer implements USB{
    public void work(USB usb){
        usb.start();
    }
    public static void main(String args[]){
        Computer computer = new Computer();
        Phone phone = new Phone();
        Camera camera = new Camera();
        computer.work(phone);//convert file...
        computer.work(camera);//convert photo...

        //接口多态
        USB phone = new Phone();
        USB camera = new Camera();
        usbs = [phone, camera]
        for usb in usbs:
            usb.work();//动态绑定
            if usb instanceof ...
                ...
    }
}

  • 接口修饰符只能是public和默认,跟class相同
  • 接口不能有构造方法,构造方法用于初始化成员变量,但是接口成员变量是常量,无需修改。而方法是不需要初始化的。
  • 接口属性隐含且只能是public final static。 且必须初始化int a = 1 //等价于public final static int a = 1
  • 接口方法默认隐含且只能是public。隐含abstarct,不能实例化
  • 继承接口要实现接口的所有抽象方法(除非A是抽象类)

    jdk8前,接口类所有方法都得是抽象方法,不能有方法体
    jdk8后,接口类可以有静态方法,默认方法(需要关键字default修饰)。

  • 一个类可以同时实现多个接口
  • 接口不能继承其他类,但可以继承extends多个别的接口。
  • 接口多态

内部类

类的第五大成员(属性,方法,构造器代码)
最大的特点就是可以访问私有属性

class Outer{//称为外部类
    int age;
    class Inner{//内部类
    }
}
  1. 局部内部类:定义在局部位置比如方法中

    • 可以直接访问外部类的所有成员,包括私有的。(直接age或重名时Outer.this.age)
    • 作用域在定义它的方法体内。
    • 不能添加访问修饰符,但是可以用final(不然可以被继承),因为相当于局部变量。
  2. 匿名内部类:很常见,简化代码编写

    • 可以直接访问外部类的所有成员,同局部内部类。
    • 格式:new 类名或接口名(参数列表){重写方法;};
    //通过tiger.getclass()可以发现底层会分配类名Outer$1
    //相当于class Outer$1 implement IA(){}
    IA tiger = new IA(){
        public void cry(){
            sout("im a tiger");
        }
    };
    tiger.cry();
    //new 类:
    //相当于class Outer$2 extends Cat{}
    //编译类型是Cat,运行类型是Outer$2
    Cat f = new Cat("kitty"){
        public void test(){...}//重写了方法
    }
    f.test();
    
    class Cat(){
        public Cat(String name){}
        public void test(){}    
    }
    interface IA(){public void cry();}
    
    • 常用实践:当作实参直接传递。 f(new 接口(){重写方法;})
      把(定义子类,重写接口中的方法,创建子类对象,调用重写后的方法)简化成一步。
    • 特点的话,除了只能使用一次,其实还有其他用处(在看spring-boot源码时发现的)当你想使用一个类的protected 方法时,但是又不和这个类在同一个包下,你是没办法调用的。这时候匿名类就派上用场了,你可以声明一个匿名类继承该类,并定义一个方法,在这个方法内使用super调用你想调用的那个方法(其实你也可以写个类继承这个类,就能调用父类的protected方法了,但是匿名类更简洁,因为你只想调用这个方法而已)

  3. 成员内部类:定义在成员位置。

    • 同样可以直接访问外部类的所有成员,包括私有
    class Outer {
        public int age = 18;    
        class Inner {
            public int age = 20;    
            public viod showAge() {
                int age  = 25;
                System.out.println(age);//25
                System.out.println(this.age);//20
                System.out.println(Outer.this.age);//18
            }
        }
    }
    
    • 4个访问修饰符都可以,因为是成员。
    • Outer方法中可以创建实例调用Inner
    • 外部其他类调用:
      Outer outer8 = new Outer()
      outer8.Inner inner = outer8.new Inner();
  4. 静态内部类

    • 跟成员内部类相比:static,只能访问静态成员。

其他

Object
getclass() 返回运行时
clone() 返回复制副本
finalize() 对象被回收时自动调用该方法。子类可以重写做一些释放资源的工作。jvm没有引用时回收,可以System.gc()显式回收
hashcode()
toString() 打印或拼接时会调用类的toString,子类往往重写
==基本类型判断值,引用类型判断地址

设计模式

单例设计模式

一个类只能存在一个对象实例。

饿汉式

class SingleTon{
    //1. 构造器私有化,防止直接new
    private SingleTon(){}
    //2. 类的内部创建对象实例
    private static SingleTon instance = new SingleTon();
    // 3. 对外暴露一个静态公共方法
    public static getInstance(){
        return instance;
    }
}

缺点: 类加载时就创建了实例 (例如只是调用一下静态成员就new了实例 ),浪费资源。

懒汉式

用时再创建,克服饿汉缺点,但线程不安全

class SingleTon{
    private SingleTon(){}
    private static SingleTon instance ;
    public static getInstance(){
        if(singleTon == null)
            instance = new SingleTon();
        return instance;
        //这三步线程不安全,可以创建多个实例
    }
}

模板设计模式

(抽象类实践)
需求:多个类完成不同任务,并统计各自完成任务的时间

abstract class Template{
    public abstract void job();
    public double caltime(){
        time start;
        job();//动态绑定机制
        time end;
        return end - start;
    }
}
posted @ 2022-04-01 01:30  开饭了没  阅读(24)  评论(0)    收藏  举报

test页脚