继承语法
在创建子类对象的时候,会执行父类相关的构造方法的理解:
子类可以使用父类的public,protected修饰的成员变量和方法,如果父类不进行初始化,在子类调用的时候就会造成未初始化的一些异常,所以在子类创建对象的时候,会先执行父类相关的构造方法。
这跟static类似。被static修饰的方法只能调用被static修饰的成员变量和方法。因为被static修饰的成员变量和方法是类变量和类方法,是静态成员,是在类装载的时候就初始化或者加载,但是没有被static修饰的成员变量和方法时非静态成员,是对象变量和对象方法,是创建对象的时候才初始化和加载,所以如果静态方法能调用非静态方法,就可能会出现非静态变量为初始化,为空的情况,就会导致一些异常。
带参数的构造器
一个类中如果没有构造方法,系统会默认给该类一个无惨构造,但是如果一个类中有构造方法,就不会有默认构造方法了。
如果基类中没有无惨构造,只有有参构造,子类在基础的时候,必须要使用super(参数)的方法调用父类相关的构造方法,否则会报错。

名词屏蔽
注意几个概念
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;
}
就会包错

向上转型
我们先看下向上转型的例子:
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修饰的对象不能再被赋值为其他对象,但是被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修饰的类不能被继承

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

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

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);
}
}
网友评论