java中类的继承
首先,让我们了解一下什么是继承?
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。
JAVA的继承是通过已存在的类作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能。
继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。所以是面向对象这一块需要掌握的重点。
通过extends来建立类与类之间的关系
public class A{}//定义一个类A
public class B extends A(){}//B继承A
首先,我们要明确在什么时候使用继承?当多个类中存在很多相同属性和行为时,将这些内容单独抽取到一个类中作为父类(超类),这样可以提高代码的复用性,降低代码的开发周期。举个例子:狗是一个大类,狗还可以被分为哈巴狗、哈士奇等多种品种,他们因为有共同点所以统称为狗。这里的狗就相当于父类,而哈巴狗、哈士奇等多种品种就相当于子类。
就像父亲和儿子的关系一样,一个父亲可以有很多儿子,而一个儿子只能有一个亲爹。继承也是如此,一个父类可以被多个子类继承,而一个子类只能继承一个父类,当然子类仍然能作为父类被继承。
public class A(){}
public class B extends A(){}
public class C extends A(){}//一个父类可以被多个子类继承
public class F extends B(){}//子类仍然能作为父类被继承
public class D(){}
//下面的写法是不对的,一个子类不能继承两个父类
public class E extends A,D(){}
一个子类继承多个父类的话,如果多个父类中出现相同的方法,子类就没法明确到底执行哪个父类的方法了,所以一个子类只能继承一个父类。
继承之后有一下特点:
(1)子类可以直接访问父类中的非私有的属性和方法。
public class 继承 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name="haha";
homeDog homedog = new homeDog();
homeDog.getname();
homeDog.run();
}
}
public class Dog {
public String name;
public String sex;
public void run(){
System.out.println("让我们一起锻炼身体");
}
}
public class homeDog extends Dog{
public void getname(){
System.out.println("我叫"+name);
}
}
有些人在试过这个代码后可能会有疑问,为什么为什么这里出现的会是null,所以我先说明一下,我们通过将Dog实例化获得了dog,此后再给dog的属性name赋值。已经被实例化之后再给属性赋值,那么这个值就不会被子类继承。如果父类在定义属性时就给属性赋值,那么这个值就可以被子类使用了。就像这样:
public class Dog {
public String name="哈士奇";
public String sex;
public void run(){
System.out.println("让我们一起锻炼身体");
}
}
说这么多只是想告诉大家子类可以直接访问父类中的非私有的属性这句话,相当于父类中的属性是子类共有的属性,不需要重新在子类中定义这些属性就可以直接给属性赋值了。就好像我在狗这个父类中设置了名称和性别这两个属性,其子类哈巴狗,哈士奇等就不需要再定义这些属性了,可以直接给哈巴狗命名并写出它的性别了,而不是子类可以引用父类初始化之后的属性的值。所以上面的代码只要把dog.name="haha"
改成homedog.name="haha"
就不会出现上面为空的情况了。
(2)子类无法继承父类中私有的内容。
如果父类的属性或者是方法用private私有化之后子类就无法继承了。
(3)以此出现了protected访问权限修饰符,被protected所修饰的成员会被位于同一package中的所有类访问到。同时,被protected所修饰的成员也能被该类的所有子类继承下来。其他package的并且不是该类的子类就不可以被继承了
public class Dog {
protected String name;//protected访问权限修饰符
protected String sex;
protected void run(){
System.out.println("让我们一起锻炼身体");
}
}
(3)若子类从父类继承过来,不能满足子类特有的需求时,子类就需要重新书写父类中对应的方法,这就要引入方法重写了。
首先我们介绍一下继承之后如何进行重写?
就是将父类出现过的方法在子类重新定义该方法,然后再写上新的方法体。下面让我们来举个例子:
public class 继承 {
public static void main(String[] args) {
Dog dog = new Dog();
homeDog homedog = new homeDog();
homedog.run();
}
}
public class Dog {
protected String name;
protected String sex;
protected void run(){
System.out.println("让我们一起锻炼身体");
}
}
public class homeDog extends Dog{
public void run(){//方法的重写
System.out.println("我是家狗,家狗不需要锻炼");
}
}
我们在方法重写的时候要注意:
1.方法重写的方法返回值、方法名、参数列表一定要一致
2.方法重写之前会运用父类中的该函数,重写后会运用子类中的该方法
进行方法重写时,我们还要遵循以下的规则:
1.子类抛出的异常不能超过父类相应方法抛出的异常
2.子类方法的访问级别不能低于父类相应方法的访问级(public>protected)
3.父类中方法若使用private、static、final任意修饰符修饰,那么不能被子类重写
我们在上面说了方法重写后会运用子类的该方法,那如果在使用中我们要用到父类的该方法要怎么使用,由此我们引出了super
,那我们接下来说一说super
的用法。super
可以用来指父类
public class 继承 {
public static void main(String[] args) {
Dog dog = new Dog();
homeDog homedog = new homeDog();
homedog.run();
}
}
public class Dog {
protected String name;
protected String sex;
public void run(){
System.out.println("让我们一起锻炼身体");
}
}
public class homeDog extends Dog{
public void run(){
super.run();//引用父类的方法
System.out.println("我是家狗,家狗不需要锻炼");
}
}
当然也可以用super
来引用父类的属性,因为不是很常见,所以我们就不举例了。
接下来我们来说一下继承的构造函数吧
创建子类对象时,父类构造方式也会被调用,为什么?
因为子类要使用到父类的数据,那么要通过父类的构造方法来初始子类的数据。
当子类自己书写了构造方法但没有用super
引用父类的构造方法或者创建子类的对象时采用默认的构造方法(即没有自己书写构造方法),那么父类默认的构造方法super();
也会被调用。
public class homeDog extends Dog{
public homeDog(){//此时采用父类默认的构造方法
System.out.println("我是家狗");
}
}
注意一旦父类自己定义了构造方法就没有了默认的构造方法。当父类有无参构造方法时,若没用super
调用父类的构造方法。就会调用父类无参的构造方法,如果没有无参的构造方法还没用super
就会报错。所以当父类中没有空参数的构造函数时,子类的构造函数必须通过super
语句指定要访问的构造函数。
class Dog{
protected String name;
private String sex;
public Dog(String name,String sex){
this.name=name;
this.sex=sex;
System.out.println(name+"我是一只狗");
}
public void setname(String name){
this.name=name;
}
protected void eat(){
System.out.println("吃饭");
}
}
class homeDog extends Dog{
public homeDog(String name){
//使用super调用父类中的构造方法
super(name,"公");
}
public void print(){
System.out.println(super.name);
}
public void eat(){
super.eat();
System.out.println("我是只家狗,我吃的都是山珍海味");
}
}
super
语句和this
语句一样必须方法构造方法的第一条,所以他们两不能同时出现在构造方法中。
最后我们要说到一个特殊的关键字final
。
他有以下的特点:
1.final
修饰的类是不可以被继承的。
2.final
修饰方法,不能被重写。
3.final
修饰变量时,这个变量就是一个常量了,他无法再被修改。
public class 继承 {
public static void main(String[] args) {
Dog dog = new Dog();
homeDog homedog = new homeDog();
}
}
public class Dog {
public static final int age = 2;
protected String name;
protected String sex;
}
public class homeDog extends Dog{
public homeDog(){//此时采用父类默认的构造方法
System.out.println("我是家狗,我今年"+age+"岁");
}
}