javaSE继承,接口与多态

类的继承

继承在面向对象中的一个重要思想,它可以使整个程序框架具有一定的弹性。在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性
继承,其基本思想是基于父类进行扩展,得到一个新的子类。子类可以继承父类的属性和方法。
在这里插入图片描述
创建一个Test类,同时创建一个继承Test类的Test2子类,其中包括重写父类的成员方法和新增的成员方法

public class Test {
   public Test(){
       //构造方法
   }
   public void dosome(){
       //成员方法
   }
   protected Test doIt(){
       return new Test();
   }
}
public class Test2 extends Test{
       public Test2(){   //构造方法
           super();      //调用父类构造方法
           super.dosome();  //调用父类成员方法
       }
       public void dosomenew(){
           //新增成员方法
       }
       public void dosome(){
           //重写父类方法
       }
       protected Test2 doIt(){   //重写父类方法
             return new Test2();
       }
}

上述Test2类的构造方法中使用super关键字调用父类的构造方法和成员方法
Test2类继承Test类。在子类中可以连同初始化父类构造方法来完成子类初始化操作,既可以在子类的构造方法中使用super()语句调用父类的构造方法,也可以在子类中使用super关键字调用父类的成员方法等。但是子类没有权限调用父类中被修饰为private的成员方法,只可以调用public或protected的方法。
重写: 继承不只是扩展父类的功能,还可以重写父类的成员方法。重写(还可以称为覆盖)就是在子类中将父类的成员方法名字保留,重写成员方法的实现内容,更改成员方法的储存权限,或是修改成员方法的返回值类型。继承中还有一种特殊的重写方法,子类与父类的成员方法返回值,方法名称,类型及个数完全相同,唯一不同的是方法内容,这种特殊方法称为重构。
当重写父类方法时,修改方法的修饰权限只能从小范围到大范围改变,例如:父类中的dosome()方法的修饰权限为protected,继承后子类中的方法dosome()只能修改为public ,不能修改为private
子类重写的方法还可以修改方法的返回值类型。(只是在J2SE 5.0以上版本中支持) 例如:父类的doIt()方法的返回值类型为Test,而子类中的doIt()方法返回值类型为Test2。重写的返回值类型必须是父类中同一方法返回值类型的子类

class Test {
   Test(){
       System.out.println("调用父类Test的构造方法");
   }
}
class Test2 extends Test{
       Test2(){   //构造方法
           System.out.println("调用子类Test2的构造方法");
       }
}
public class Test3 extends Test2 {
    public Test3(){
        System.out.println("调用子类Test3的构造方法");
    }
    public static void main(String[] args) {
        Test3 t=new Test3();
    }
}

输出结果:
调用父类Test的构造方法
调用子类Test2的构造方法
调用子类Test3的构造方法

可以看出,我们并没有在子类Test3的构造方法中调用任何父类的构造方法,但是在实例化Test3的时候,却调用了父类的构造方法并且调用构造方法的顺序是,先是顶级父类,然后是上一级父类,最后是子类。也就是说实例化子类对象时,要先实例化父类对象,然后再实例化子类对象。所以在子类构造方法访问父类的构造方法之前,父类已完成实例化操作。
在实例化子类的对象时,父类无参构造方法将被自动调用。有参构造方法不呢个被自动调用,用户只能使用super关键字显示地调用父类的构造方法。

如果使用finalize()方法对对象进行清理,需要确保子类finalize()方法的最后一个动作是调用父类的finalize()方法。以保证当垃圾回收对象占用内存时,对象的所有部分都能被正常终止。

Object类

Object类是一种特殊的类,它是所有类的父类,是java类层中最高层的类。用户创建一个类时除非已经指定要从其他类继承,否则它就是从Object类继承过来的。java中的每个类都源于Object类,如String,Integer类都是继承与Object类。除此以外,自定义的类也都继承与Object类。由于所有子类都是Object的子类,所以不需要加extends Object
在Object类中包括clone(),finalize(),equals(),toString()方法。由于所有类都是Object类的子类,所以任何类都可以重写Object类中的方法(一些方法除外)。
Object类中的getClass(),notify(),notifyAll(),wait()等方法不能被重写,因为他们被定义为final类型

(1).getClass()方法

getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName()方法可以取得类的名称

getClass().getName();

可以将getClass()与toString()方法联合使用

(2).toString()方法

toString()方法是将一个对象返回为字符串形式,它会返回一个String实例。实际应用中,通常重写toString方法,为对象提供一个特定的输出模式。当这个类转换为字符串或与字符串连接时,会自动调用重写的toString方法

public class Demo2 {
    public String toString(){
        return getClass().getName()+"类中的重写toString方法";
    }
    public static void main(String[] args) {
        Demo2 d=new Demo2();
        System.out.println(d);
        System.out.println(d.toString());  //打印本类对象
    }
}
输出结果:
com.code.Demo2类中的重写toString方法
com.code.Demo2类中的重写toString方法
(3).equals()方法

"==“与equals()方法的区别,”=="比较的是两个对象的引用是否相同,而equals()方法比较的是两个对象的实际内容。

class Test {
}
class Test2{
    public static void main(String[] args) {
        String s1="123";
        String s2="123";
        System.out.println(s1.equals(s2));
        Test t1=new Test();
        Test t2=new Test();
        System.out.println(t1.equals(t2));
    }
}

输出结果:
true
false

可以看出,在自定义类中使用equals()方法进行比较时,返回false,这是因为equals()方法的默认实现是使用"=="运算符比较两个对象引用地址,而不是比较对象的内容,所以要想真正做到比较两个对象内容的比较,需要在自定义类中重写equals()方法。String类返回的是true是因为String类重写了equals()方法

三·对象类型的转换

(1).向上转型

比如平行四边形是特殊的四边形,平行四边形是四边形的一种,那么就可以将平行四边形对象看作是一个四边形对象。

public class Quadrangle {     //四边形类
    public static void draw(Quadrangle q){
         System.out.println("这是父类");
    }
}
public class Parallelogram extends Quadrangle {   //平行四边形类
    public static void main(String[] args) {
        Parallelogram p=new Parallelogram();
        draw(p);  //draw方法是static,所以它的子类可以直接调用
    }
}

输出结果:
这是父类

平行四边形类继承了四边形的类,四边形类存在一个draw()方法,它的参数是Quadrangle类型,但是在子类中调用时却给予的参数类型却是Parallelogram类。Parallelogram是Quadrangle的一个子类,所以,Parallelogram对象可以看作是Quadrangle的一个对象。相当于Quadrangle q=new Parallelogram();就是把子类对象赋值给父类类型的变量,这称为向上转型
比如其他四边形类型的对象(四边形类的子类,比如你定义正方形类,梯形类都继承与四边形类)可以作为四边形类的draw()的参数,如果在draw()方法中根据不同的对象设置不同的处理,就可以做到在父类中定义一个方法完成各个子类的功能,这样可以使同一份代码毫无差别地运用到不同类型之上,这就是多态机制的基本思想。
由于向上转型是从一个较具体的类到抽象的类的转换,所以它总是安全的。比如,我们可以说平行四边形是特殊的四边形,但不能说四边形是平行四边形。

(2).向下转型

向下转型是将抽象的类转换为较具体的类。这样的转型通常会出现问题,比如不能说四边形是平行四边形的一种,所有鸟都是大雁。子类对象总是父类的一个实例,但父类对象不一定是子类的一个实例。

public class Quadrangle {
    public static void draw(Quadrangle q){
        System.out.println("这是父类");
    }
}
public class Parallelogram extends Quadrangle {
    public static void main(String[] args) {
        draw(new Parallelogram());   //向上转型
        Quadrangle q=new Parallelogram();     //向上转型
        //Parallelogram p=q;      父类对象赋值给子类对象会报错
        Parallelogram p=(Parallelogram)q;   //父类对象赋值给子类对象,并强制转换为子类对象是对的
    }
}

将父类对象强制转换为某个子类对象,称为显式类型转换
在程序中使用向下转型时,必须使用显示类型转换,指明要将父类对象转换为哪一种类型的子类对象

四·instanceof操作符判断对象类型

当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型时,可以使用instanceof操作符判断父类对象是否为子类对象的实例。可以使用instanceof操作符判断是否一个类实现了某个接口,也可以判断一个实例对象是否属于一个类
instanceof语法

某类对象的引用 instanceof  某个类

使用instanceof操作符的表达式返回值为布尔值。如果返回值为true,说明某个类的对象是某一个类的实例对象。如果返回值为false,说明某个类对象不是某个类的实例

public class Father {
    
}
public class son extends Father {
}
class Test {
}
public class son2 extends Father {
    public static void main(String[] args) {
        Father f=new Father();  //实力化一个父类对象
        if(f instanceof  son){  //判断父类是不是son子类的一个实例
            son s=(son)f;   //强制转换为son类
        }
        if(f instanceof  son2) {  //判断父类是不是son子类的一个实例
            son2 s = (son2) f;  //强制转换为son2类
        }
        //System.out.println(f instanceof Test);  因为f不是Test类的对象,所以这句会编译报错
    }
}

五·方法的重载

构造方法的名称由类名决定,所以构造方法只有一个名称。如果需要以不同方式来实例化对象,就需要使用多个构造方法来完成。这些构造方法都需要根据类名进行命名,为了使方法名相同而使形参不同的构造方法同时存在,必须用到方法重载。
方法的重载就是在同一个类中允许存在一个以上同名的方法,只要这些方法的参数个数不同或类型不同或参数的顺序不同(需要参数类型不同然后顺序不同)。
只有返回值不同不足以区分两个方法的重载
参数个数不同时重载,可以定义不定长参数方法

 public static int add(int...a){
        int s=0;
        for(int i=0;i<a.length;i++)
            s+=a[i];
        return s;
    }

在参数列表中使用"…"形式定义不定参数,其实这个不定参数a就是一个数组,编译器会将(int…a)这种形式看作是(int[] a)

六·多态

利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。
例如,在向上转型中子类对象可以作为父类对象的实例使用。如果需要在一个子类中定义一个方法,然后另一个子类定义一个方法,但是这两个方法实现的功能是相同的。在调用时就会出现冗余,需要分别定义着两个子类。但是我们可以利用向上转型,定义一个父类,在这个父类上定义这个方法。这样可以解决代码冗余,同时也易于维护

public class Square extends Quadrangle{
    public Square(){
        System.out.println("正方形类");
    }
}
public class Parallelogram extends Quadrangle {
   public Parallelogram(){
       System.out.println("平行四边形");
   }
}
public class Quadrangle {
    private Quadrangle[] qList=new Quadrangle[6];
    private int nextindex=0;
    public  void draw(Quadrangle q){
        if(nextindex < qList.length){
            qList[nextindex]=q;
            System.out.println(nextindex);
            nextindex++;
        }
    }
    public static void main(String[] args) {
        Quadrangle q=new Quadrangle();
        q.draw(new Square());
        q.draw(new Parallelogram());
    }
}
输出结果:
正方形类
0
平行四边形
1

以不同的类对象调用draw()方法,可以处理不同的图形问题。使用多态节省了开发和维护时间。只需要实例化一个继承父类的子类对象,就可调用。

七·抽象类和接口

(1)抽象类

在类与对象中说过抽象类,一般父类定义为抽象类,需要使用这个父类进行继承和多态处理。越是在上方的类越抽象。在多态机制中,并不需要将父类初始化对象,我们需要的是子类对象,所以在java中设置抽象类不可以实例化对象。

public abstract class Test(){   /定义抽象类
	abstract void method();   //定义抽象方法
}

abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法,抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,抽象类除了被继承之外没有任何意义。
声明一个抽象的方法,就必须将承载这个抽象方法的类定义为抽象类,不可能在非抽象类中获取抽象方法。只要类中有一个抽象方法,此类就被标记为抽象类。
抽象类被继承后需要实现其中所以的抽象方法,也就是保证相同的方法名称,参数列表和相同返回值类型创建非抽象方法,也可以是抽象方法。
继承抽象类的所有子类需要将抽象类中的抽象方法进行覆盖。但这样就会出现冗余代码,同时还会出现一个问题,比如某一个子类不需要这个方法但它又不得不去重写这个抽象方法。如果将这个抽象方法单独拿出来放在一个类中,让那些需要这个方法的子类继承这个类,不需要这个方法的类继承本来的父类,但这又会出现一个问题,需要那个抽象方法的子类又不继承本来的父类了。所有的子类都要继承父类,但只有一些子类需要抽象方法,而java中又不允许继承多个类,所以这就需要接口

(2)接口

接口是抽象类的延伸,可以将它看作是存粹的抽象类,接口中的所有方法没有方法体,可以将一个方法封装到一个接口中,需要这个方法的类实现这个接口。同时不管需不需要的这个方法的类都可以去继承父类。

public interface text{      //interface : 接口关键字
		void dosome();     //接口内的方法,省略abstarct关键字
}

一个类实现一个接口可使用implements关键字

public class Son extends Father implements text{
    //......
}

在接口中,方法必须被定义为public或abstract形式,即使不将该方法定义为public形式,它也是public
在接口中定义的任何字段都自动是static和final

public interface drawInterface {
    public void draw();
}
public class Square extends Quadrangle implements drawInterface{
    public void draw(){
        System.out.println("正方形类.draw()");
    }
}
public class Parallelogram extends Quadrangle implements drawInterface{
   public void draw(){
       System.out.println("平行四边形.draw()");
   }
}
public class Quadrangle {
    public static void main(String[] args) {
        drawInterface[] d={new Square(),new Parallelogram()};  //接口也可以实现向上转型操作   对象数组
        for(int i=0;i<d.length;i++){
            d[i].draw();
        }
    }
}

输出结果:
正方形类.draw()
平行四边形.draw()
(3)接口与继承

一个类可以实现多个接口,使用逗号隔开,但这可能会在一个类中产生庞大的代码量,因为实现一个接口时需要实现接口中的所有方法

class 类名 implements 接口1,接口2......接口n

在定义一个接口时也可以继承另一个接口

interface inf1{
}
interface inf2 extends intf1{
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值