什么是继承:java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系
public class B extends A{
}
//A称为父类(基类或超类)
//B称为子类(派生类)
继承的特点
- 子类能继承父类的非私有成员(成员变量、成员方法)
继承后对象的创建
- 子类的对象是由子类、父类共同完成的
使用继承的好处
减少重复代码的编写
继承相关的注意事项
权限修饰符
用来限制类中的成员(成员变量、成员方法、构造器、代码块)能够被访问的范围
权限修饰符的种类及作用
缺省:缺省就是没有修饰符 啥也不写
比如现在有package1和package2两个包
package1下有两个类A和B
package2下有一个类C和A的子类A_zi
在package1中的A中定义了四个方法(分别是由四个不同的修饰符修饰的)
此时在类A中访问private修饰的方法
可以看出是可以访问的
此时我们在同一个包下的B类尝试访问四个不同的方法
发现private修饰的方法的确无法访问
然后我们在另一个包中让子类A_zi访问四个方法
发现私有的(private)和缺省的(没有修饰符)都出现了报错,说明超过了他们的范围
最后我们这个包二中的另一个类C(不是A的子类)去访问这四个方法
结果发现protected修饰的方法也访问不了了
单继承
Java是单继承的,Java中的类不支持多继承,但是支持多层继承
这就好像一个人只能有一个亲生父亲,而不能有多个亲生父亲是差不多的意思
object类
object类是java所有类的祖宗类,也就是说,我们写的任何一个类都是object类的子类
方法重写
什么是方法重写:当认为父类的某个方法不好用,或者无法满足子类需求,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的方法
//B类
public class B extends A{
public void print1(){
System.out.printIn("111")
}
}
//A类
public class A{
public void print1(){
System.out.printIn("999"); //方法重写
}
public void print2(int a,int b){
System.out.printIn("999999");
}
}
//Test类
public class Test(){
public static void main(String[] args){
B b = new B();
b.print1();//输出方法重写后的999
b.print2(2,3);
}
}
注意:方法重写后,java遵循就近原则
注意事项:
- 重写小技巧:使用override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好
-
@Override public void print1(){ Ssytem.out.printIn("123456"); }
- 子类重写父类方法时,访问权限必须大宇等于父类该方法的权限
- 重写方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小
- 私有方法,静态方法不能被重写
方法重写的应用场景:
子类重写Object类的toString()方法,以便返回对象的内容
有时候需要输出某个对象他的值而非他的地址(原来的toString方法输出地址),所以这个时候toString方法满足不了我们的需求,就需要对方法进行重写
@Override
public String toString(){
return "Student{"+"name='"+name+'\''+",age="+age+'}';
}
当然这个操作也可以直接右键 找到generate然后再找到toString()然后选中成员变量,OK就完成了
子类访问成员的特点
- 在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的
//A.java
public class A extends B{
String name = "子类名称";
public void showName(){
System.out.printIn(name);
}
}
//B.java
public class B{
String name = "父类名字";
}
此时有两个name,输出的就是子类名称(根据就近原则),但假设存在一个局部变量就在这个方法里面:
//A.java
public class A extends B{
String name = "子类名称";
public void showName(){
String name = "局部名称";
System.out.printIn(name);
}
}
//B.java
public class B{
String name = "父类名字";
}
此时输出的就是“局部名称”,因为根据就近原则,就输出方法里的变量name了,如果此时需要输出类变量name的话,可以使用this关键字:
System.out.printIn(this.name);
此时如果想输出的是父类里的name呢?可以使用java提供的关键字super,super会指定去找该类的父类
System.out.printIn(super.name);
这里就会去寻找该类的父类的成员变量name
成员变量是这样的,成员方法:子类重写的方法,如果去访问就会优先输出重写的(就近原则),如果还是想访问父类的,可以使用super关键字,和成员变量是同样的使用方法。
子类构造器的特点
- 子类的全部构造器,都会先调用父类的构造器,再执行自己
class F{
public F(){
System.out.printIn("==父类F的 无参数构造器 执行了==");
}
}
class Z extends F{
public Z(){
System.out.printIn("==子类Z的 无参数构造器 执行了==");
}
}
public class Test{
public static void main(String[] args){
Z z = new Z();
}
}
//结果:
//==父类F的 无参数构造器 执行了==
//==子类Z的 无参数构造器 执行了==
为什么子类构造器都会调用父类的无参数构造器?因为子类的构造器代码里面的第一行都会有一个super去调用父类的无参数构造器。此时如果父类中有了有参构造器,就会报错(因为子类没有无参构造器可以调用了)------->怎么样让他不报错就去调用有参构造器呢?
class F{
public F(String name,int age){
System.out.printIn("==父类F的 有参数构造器 执行了==");
}
}
class Z extends F{
public Z(){
super("sangria")
System.out.printIn("==子类Z的 无参数构造器 执行了==");
}
}
public class Test{
public static void main(String[] args){
Z z = new Z();
}
}
//结果:
//==父类F的 有参数构造器 执行了==
//==子类Z的 无参数构造器 执行了==
只需要在子类构造器中super去加上参数调用父类的有参构造器即可
super、this调用兄弟构造器
任意类的构造器中,可以通过this(...)去调用该类的其他构造器
this(...)、super(...)都只能放在构造器的第一行,因此,有了this(...)就不能写super(...)了,反之亦然。