Java

Java编程思想 复用类

2020-05-01  本文已影响0人  静享时光

继承语法

在创建子类对象的时候,会执行父类相关的构造方法的理解:
子类可以使用父类的public,protected修饰的成员变量和方法,如果父类不进行初始化,在子类调用的时候就会造成未初始化的一些异常,所以在子类创建对象的时候,会先执行父类相关的构造方法。
这跟static类似。被static修饰的方法只能调用被static修饰的成员变量和方法。因为被static修饰的成员变量和方法是类变量和类方法,是静态成员,是在类装载的时候就初始化或者加载,但是没有被static修饰的成员变量和方法时非静态成员,是对象变量和对象方法,是创建对象的时候才初始化和加载,所以如果静态方法能调用非静态方法,就可能会出现非静态变量为初始化,为空的情况,就会导致一些异常。

带参数的构造器

一个类中如果没有构造方法,系统会默认给该类一个无惨构造,但是如果一个类中有构造方法,就不会有默认构造方法了。
如果基类中没有无惨构造,只有有参构造,子类在基础的时候,必须要使用super(参数)的方法调用父类相关的构造方法,否则会报错。


不调用父类的构造方法,程序报错.png

名词屏蔽

注意几个概念
1、一个类中有几个方法同名,但是参数不同时是重载
2、子类和基类的方法名相同,参数相同,叫覆写,或叫重写
3、子类和基类的方法名相同,参数不同时,也叫重载父类的方法
4、子类和基类的方法名相同,参数也相同,但是返回值不同时,会报错

package multiplex_demo;

class Homer {
    char doh(char c) {
        System.out.println("Homer  doh(char)");
        return c;
    }

    float doh(float f) {
        System.out.println("Homer  doh(float)");
        return f;
    }
}

class Milhouse {

}

class Bart extends Homer {
    void doh(Milhouse m) {
        System.out.println("Bart  doh(char)");
    }
    float doh(float f) {
        System.out.println("Bart  doh(float)");
        return f;
    }
}

public class Hide {
    public static void main(String[] args) {
        Bart bart = new Bart();
        bart.doh(1);
        bart.doh('x');
        bart.doh(1.0f);
        bart.doh(new Milhouse());
    }

}

如果把
float doh(float f) {
System.out.println("Bart doh(float)");
return f;
}
改为
double doh(float f) {
System.out.println("Bart doh(float)");
return (double )f;
}
就会包错


同名同参数不同返回值.png

向上转型

我们先看下向上转型的例子:

package multiplex_demo;

class Instrument {
    public void play() {
        System.out.println("Instrument play 方法执行了");
    }

    public static void tune(Instrument instrument) {
        instrument.play();
    }

    public void deal() {
        System.out.println("Instrument deal 方法执行了");
    }
}

class Stringed extends Instrument {
    public void play() {
        System.out.println("Stringed play 方法执行了");
    }
}

class Wind extends Instrument {
    public void play() {
        System.out.println("Wind play 方法执行了");
    }
}

public class Music {
    public static void main(String[] args) {
        Wind wind = new Wind();
        //tune需要传的参数类型是Instrument,这里我们传的是Wind,
        // 就相当于把Wind对象转换为了Instrument对象,这个就是向上转型
        Instrument.tune(wind);

        //用向上转型的好处就是在该类中就不用写多个tune方法
        Stringed stringed = new Stringed();
        Instrument.tune(stringed);
        //因为Stringed类中没有deal()方法,所以执行父类的deal方法
        stringed.deal();
    }
}

如果我们不向上转型的话,在Music类中就要写多个tune方法。代码不够简洁。
需要注意的是,如果子类覆写父类的方法时,调用的时候执行的是子类的方法,如果子类中没有匹配的方法时,就只想父类相匹配的方法。

向上转型是较专用类型想通用类型转型,所以是安全的。但是值得醉意的是向上转型的过程中,可能会丢失成员。如果是子类特有的成员时,就会丢失。因为这些成员父类是没有的,所以也是不能调用的。

final关键字

final关键字可以修饰方法,变量和类,使用时需要注意:

1、被final修饰的变量是常量,值不能修改

被final修饰的变量的值是不变的,也就是常量。注意,如果被final修饰的变量是引用类型,变量不能被赋值为其他对象,但是对象的内容是可以进行修改的


被final修饰的对象不能再被赋值为其他对象.png

被final修饰的对象不能再被赋值为其他对象,但是被final修饰的对象的内容是可以改变的。

class Parent {

    private String name;

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return name;
    }
}

class Child {

    //parent被final修饰
    final Parent parent = new Parent("xiaoLi");

    public void changeName(String name) {
    //修改parent对象的name值
        parent.setName(name);
    }

    public void getData() {
        System.out.println("name: " + parent.getName());
    }
}

public class FinalClass {

    public static void main(String[] args) {
        Child child = new Child();
        child.changeName("xiaoHong");
        child.getData();
    }
2、被final修饰的类不能被继承
被final修饰的类不能被继承.png
3、final不能修饰接口

原因分析:因为接口必须得有实现类才能使用,但是被final修饰的类不能有子类,所以接口就失去了意义。所以接口不能用final修饰。


final不能修饰接口.png

4、被final 修饰的方法不能被覆写

final修饰的方法不能被覆写.png
5、注意被static final 和final修饰的成员的不同
class Value {
    public int i;

    public Value(int i) {
        this.i = i;
    }
}

public class FinalClass2 {
    private static Random rand = new Random(47);
    private String id;

    public FinalClass2(String id) {
        this.id = id;
    }

    private final int i4 = rand.nextInt(20);
    private static final int INT_5 = rand.nextInt(20);
    private Value v1 = new Value(11);
    private final Value v2 = new Value(22);
    private static final Value VAL_3 = new Value(33);
    private final int[] a = {1, 2, 3, 4, 5, 6};

    @Override
    public String toString() {
        return " id: " + id + "\n" +
                "i4: " + i4 + "\n" +
                "INT_5: " + INT_5 + " \n";
    }

    public static void main(String[] args) {
        FinalClass2 fd1 = new FinalClass2("fd1");
        fd1.v2.i++;
        System.out.println("fd1.v2.i: " + fd1.v2.i);//输出为23,由此可以看出虽然V2被修饰了,
        // 但是V2对象的数据内容是可以修改的
        fd1.v1 = new Value(9);
        for (int i = 0; i < fd1.a.length; i++) {
            fd1.a[i]++;
        }
        for (int i = 0; i < fd1.a.length; i++) {
            //输出结果为2 ,3 ,4 ,5 ,6 ,7 ,
            // 所以,虽然数组被final修饰,但是数组的元素值是可以改变的。
            // 这一点和被final修饰的对象的内存可以改变是同样的道理
            System.out.print(fd1.a[i] + " ,");
        }
        System.out.println();
        System.out.println("=========================== " );
        /**
         * fd1:  id: fd1
         * i4: 15
         * INT_5: 18
         * 打印fd1
         */
        System.out.println("fd1: " + fd1);
        System.out.println("创建一个新的对象");
        FinalClass2 fd2 = new FinalClass2("fd2");
        /**
         * fd2:  id: fd2
         * i4: 13
         * INT_5: 18
         *
         * 两次创建的对象,i4值不一样,但是两次的INT_5值时一样的。
         * i4是被final修饰的,在创建对象的时候进行初始化,通过Random获取一个值
         * 而INT_5是被static final修饰,被static修饰的变量是在类加载的时候就初始化,
         * 并不是在创建对象的时候初始化。所以两次INT_5的值一样。
         */
        System.out.println("fd2: " + fd2);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读