insist on 01 静态、继承、多态详解及注意事项

243 阅读7分钟

静态,继承,多态


静态(static)

什么是静态?

Java中的静态是什么?
static是静态的意思,是一个修饰符,就像是一个形容词,是用来形容类,变量,方法的。
static修饰变量,这个变量就变成了静态变量,修饰方法这个方法就成了静态方法,
static关键字方便在没有创建对象的情况下来进行调用(方法/变量)。
静态方法的好处就是不用生成类的实例就可以直接调用。
static方法修饰的成员不再属于某个对象,而是属于它所在的类。只需要通过其类名就可以访问,不需要再消耗资源反复创建对象。
在类第一次加载的时候,static就已经在内存中了,直到程序结束后,该内存才会释放。
如果不是static修饰的成员函数,在使用完之后就会立即被JVM回收。

static变量

静态变量的获取属性的方式(特点:在类加载的时候就已经加载,在内存中,只有一份,被所有的对象共享)
	1 类名.属性名
	2 对象名.属性名(不推荐);
成员变量的获取方式(随着对象的加载而加载,每new一个对象就会开辟一块新内存)
	对象名.属性名
	注意:只能获取非私有的属性变量

静态变量实现举例

public static void main(String[] args) {
        String name = Student.name;
        Student s = new Student();
        String name1 = s.name;//静态变量可以直接被类访问 也可以被对象访问

        int age = s.age;
//        int age1 = Student.age; 对象变量只能被对象访问
    }

方法

静态方法的获取属性的方式
	1 类名.方法名
	2 对象名.方法名(不推荐);
实例方法的获取方式(随着对象的加载而加载,每new一个对象就会开辟一块新内存)
	对象名.方法名
	注意:只能获取非私有的方法

静态方法实现举例

Student.printhelloworld();//类方法可以直接被类调用
        Student s = new Student();
        s.printhelloworld();//类方法,也可以被对象调用 ,但不推荐
        s.helloworld();//实例方法可以直接被对象调用
//        Student.helloworld(); 实例方法不能被类方法调用

代码块

静态代码块
	格式
	static{} 应用场景 初始化静态资源的时候
实例代码块
	格式
	{} 应用场景 初始化实例变量

易错点

易错点:
1、静态中不能使用实例相关的属性和方法。静态方法中不能使用实例的属性,不能调用实例方法。

2、实例方法只能通过实例调用。

3、实例方法中可以出现this关键字,类方法中不可以出现this关键字的

特别标注

!!!静态方法和私有方法!!!

!!!静态方法不能重写,私有方法不谈重写(无意义)!!!


单例

饿汉式单例

public class Demo {
    public static void main(String[] args) {
        A object = A.getObject();
        System.out.println(object);
        A object1 = A.getObject();
        System.out.println(object1);
    }
}
class A {
    //2创建一个私有的类变量 记住一个类对象
    private static final A a = new A();

    //1定义一个私有类的构造器
    private A(){

    }

    //定义一个类返回类的对象
    public static A getObject(){
        return a;
    }
}

饿汉式(静态变量)

  1. 构造器私有化 (防止 new );

  2. 类的内部创建对象;

  3. 向外暴露一个获得该实例对象的静态的公共方法;

    优缺点

    1. 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
    2. 缺点:在类装载的时候就完成实例化,没有达到懒加载( Lazy Loading )的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费;
    3. 结论:这种单例模式可用,可能造成内存浪费;

懒汉式单例

public class Demo {
    public static void main(String[] args) {
        B b1 = B.getobject();
        B b2 = B.getobject();
        System.out.println(b1.equals(b2));
    }
}
class B {
    //懒汉式单例写法
    //2创建一个类变量
    private static B b;
    //1一个私有的构造器
    private B(){

    }

    //3建立一个类方法,保证第一次建立对象是才进行创建
    public static B getobject(){
        if (b==null){
            b = new B();
            System.out.println("第一次拿对象");
        }
        return b;
    }
}

懒汉式(线程不安全)

优缺点:

起到懒加载的效果,但是只能在单线程下使用; 如果在多线程下,一个线程进入了 if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例;所以在多线程环境下不可使用这种方式; 结论:在实际开发中,建议不要使用这种方式;

继承extend

作用:为了抽取多个类中相同的代码,放在一个父类中,从而简化代码
格式	public class 子类  extends 父类{ }
特点:继承父类中非私有的成员变量、成员方法;
注意:1 java只支持单继承,不支持多继承,但是支持多层继承
	 2 所有的类,都是直接或者间接继承于 Object

方法重写

使用情况:当父类的方法没有办法满足子类的需求

重写的方法:子类写一个跟父类一样的方法,覆盖掉父类中的访问
注意事项:
    @Override
    private 静态方法都不能被重写

继承的举例

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.print1();
        b.print3();
        System.out.println(b.i);
        System.out.println(b.k);
    }
}
class A {
    int i ;
    public void print1(){
        System.out.println("方法一");
    }
    private int j ;
    private void print2(){
        System.out.println("方法二");
    }
}
class B extends A{
    //继承只能访问非私有的变量与方法
    int k;
    public  void print3(){
        System.out.println("方法三");
//        print1();
//        System.out.println(i);
    }

}

继承之后成员的访问

访问优先级:根据就近原则去访问
怎么访问本类中的数据 -> this.变量/方法
怎么访问父类中的数据 -> super.变量/方法

权限修饰符

5.png

多态

概念:基于继承或者实现,然后有重写的方法。
格式:父类 引用 = new 子类();
注意:1.我们在多态的情况下,调用方法,用的子类方法。
	 2.属性是没有多态的,使用的都是父类的
优点:可以使用父类作为形参,从而接收一切的子类的对象

多态的常见举例

public class Demo {
    public static void main(String[] args) {
        Person p = new Student();
        p.run();					//多态调用Student run方法
        System.out.println(p.name);

        Person p1 = new Teacher();
        p1.run();					//多态调用Teacher run方法
        System.out.println(p1.name);
    }
}
class Person {
    String name ="父类";
    public void run(){
        System.out.println("人会跑");
    }
    public Person() {
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
class Student extends Person{  //子类继承父类重写父类方法
    @Override
    public void run() {
        System.out.println("学生跑的快");
    }

    public void study(){ 				//子类私有方法 无法被多态调用,  
        System.out.println("学生学习");	//如果需要调用子类方法需要将父类对象转化为多余的子类对象
    }

    @Override
    public void sleep(){
        System.out.println("学生睡觉");
    }

    public void play(){
        System.out.println("玩起来");
    }
}
class Student extends Person{ //子类继承父类重写父类方法
    @Override
    public void run() {
        System.out.println("学生跑的快");
    }

    public void study(){
        System.out.println("学生学习");
    }

    @Override
    public void sleep(){
        System.out.println("学生睡觉");
    }

    public void play(){
        System.out.println("玩起来");
    }
}

多态的好处

  1. 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
  2. 提高了程序的可扩展性和可维护性

缺点

多态无法直接调用子类的独有方法,属于多态的缺陷

解决方法

instanceofJava的一个保留关键字,左边是对象,右边是类,返回类型是Boolean类型。它的具体作用是测试左边的对象是否是右边类或者该类的子类创建的实例对象,是,则返回true,否则返回falseinstanceof使用注意事项
	先有继承关系,再有instanceof的使用。
	当该测试对象创建时右边的声明类型和左边的类其中的任意一个跟测试类必须得是继承树的同一分支或存在继承关系,否则编译器会报错。
	instanceof JDK8之后用法,在判断时可直接转化子类对象

解决方法实例

public class Demo {
    public static void main(String[] args) {
    //使用多态进行创建对象
          Animal a1 = new Dog("大狗",100);
          method(a1);调用方法
          Animal c1 = new Cat("大猫",50);

    }

    private static void method(Animal a1) {
        a1.eat();
        if (a1 instanceof Dog a){ //直接转化子类对象并调用
            a.lookhome();
        }
        if (a1 instanceof Cat c){
            c.catchmouse();
        }

    }
}

class Animal {
    private String name;
    private double weight;

    public Animal() {
    }

    public Animal(String name, double weight) {
        this.name = name;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

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

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public abstract void eat(){
        
    }
}
class Dog extends Animal{

    public Dog() {
    }

    public Dog(String name, double weight) {
        super(name, weight);
    }

    @Override
    public void eat() {
        System.out.println(getName()+"吃骨头");
    }

    public void lookhome(){
        System.out.println(getName()+"再看家");
    }
}
class Cat extends Animal{

    public Cat() {
    }

    public Cat(String name, double weight) {
        super(name, weight);
    }

    @Override
    public void eat() {
        System.out.println(getName()+"吃鱼");
    }

    public void catchmouse(){
        System.out.println(getName()+"在抓老鼠");
    }
}