Java---接口、继承与多态

目录

 

一、类的继承

二、Object类

1. getclass()方法

2. toString()方法

3. equals()方法

三、对象类型的转换

四、使用instanceof操作符判断对象类型

五、方法的重载

定义不定长参数方法

六、多态

七、抽象类与接口

1、抽象类

2. 接口

3. 接口与继承


一、类的继承

在subroutine.java中:

class Parent{
	Parent(){
		System.out.println("调用父类的Parent()构造方法");
	}
}

class SubParent extends Parent{
	SubParent(){
		System.out.println("调用子类的subParent()构造方法");
	}
}

public class subroutine extends SubParent {
	subroutine(){
		System.out.println("调用子类的subroutine()构造方法");
	}
	public static void main(String[] args) {
		subroutine obj = new subroutine();
	}
}

运行结果为:

在实例化子类对象时,父类无参构造方法将被自动调用,但又参构造方法不能被自动调用。只能依赖于super关键字显式调用父类的构造方法。创建一个子类对象,将包含一个父类子对象。当实例化子类对象时,父类对象也相应被实例化。


(以下具体代码)

class text{
	text(){
		System.out.println("call the constructor of text()");
	}
	public void doSomething() {
		System.out.println("doSomething");
	}
	protected text dolt() {
		return new text();
	}
}
public class text2 extends text{
	text2(){
		super();
		System.out.println("call the constructor of text2()");
	}
	public void doSomething() {
		System.out.println("doSomething in class text2");
	}
	public void doNew() {
		System.out.println("doNew here");
	}
	protected text2 dolt() {
		return new text2();
	}
	
	public static void main(String[] args) {
		text2 obj = new text2();
		obj.doSomething();  //执行text2类中的方法
		obj.doNew();
		obj.dolt();   //执行text2类中的方法
	}

}

结果为:

call the constructor of text() 创建父类对象
call the constructor of text2() 创建子类对象
doSomething in class text2 调用text2中的重写方法
doNew here 调用text2中新添加的方法
call the constructor of text() 调用text2中的dolt()方法,创建对象,先创建一个父类对象
call the constructor of text2() 再创建一个子类对象

1. super关键字:

可以在子类的构造方法中调用super()语句调用父类的构造方法;也可以在子类中使用super关键字调用父类的成员方法(仅public、protected)。

2. 重写(覆盖)父类的成员方法:

将父类成员方法的名称保留,                  

1)重写成员方法的实现内容  
2)更改成员方法的存储权限: 只能从小范围改到大范围
3)修改成员方法的返回类型: 遵循:重写的返回值类型必须是父类该方法的返回值类型的子类

重写方法的调用:

   
1)用实例化对象是调用不到父类的 在内存中仍为子类对象  
2)只能用super关键字

1)且只能在类方法中调用

2)在main(类外部)是调用不到的

 
  (最初overrride的设计意图之一)  
class Father{
	Father(){}
	public void doSth() {
		System.out.println("doFather");
	}
}
public class overrideDemo extends Father {
	overrideDemo(){}
	public void doSth() {
		System.out.println("doOverride");
	}
	public void callFatherdoSth() {
		super.doSth();               //用super关键字在子类类方法中调用父类重写方法
	}
	
	public static void main(String[] args) {
		overrideDemo obj = new overrideDemo();
		obj.doSth();                 //调用子类方法
		obj.callFatherdoSth();       //通过子类中的方法,调用父类重写方法
                                             //不是用实例化对象调用的
                                             //子类方法中用super关键字调用了重写方法
	}

}

结果为:

如果要调用父类的重写方法,就在子类中加一个方法,该方法用super关键字调用父类重写方法。若多重继承,也可以这样调用,在每个子类中都加上这样的方法就可以了。

如果要调用

3. 重构:

子类与父类的成员方法:返回值相同、方法名称相同、参数类型及个数相同;仅方法实现内容不同。

二、Object类

在Java中,所有类都直接或间接继承了java.lang.Object类。Object类是所有类的父类,是java类层中最高层类。

1)在Object类中主要包括equals()、toString()、clone()、finalize()等方法。由于所有类都是Object类的子类,所以任何类都可以重写Object类中的方法。

2)Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。

1. getclass()方法

返回对象执行时的Class,然后使用此实例调用getName()方法,可以获得类的名称。还可与toString()方法联合使用

2. toString()方法

将一个对象返回为欸字符串形式,返回类型为String,返回一个String实例。实际中通常根据需要重写toString方法。

当对象转换为欸字符串或与字符串连接时,将自动调用重写的toString()方法。

public class ObjectInstance{
    public String toString(){        //toString()返回一个String实例
        return "在" + getClass().getName() + "类中重写toString()方法";
    }

    public static void main(String[] args){
        ObjectInstance obj = new ObjectInstance();
        System.out.println(obj);        //自动调用重写的toString()方法
    }
}    //输出为:“在ObjectInstance类中重写toString()方法”

3. equals()方法

“==”比较的时两个引用是否相等,而equals()方法比较的是实际内容。

而在比较两个自定义类的实例化对象时,因为equals()方法的默认实现是使用“==”运算符比较两个对象的引用地址,而不是比较对象的内容,因此通常需要在自定义类中重写equals()方法。

class V_one{
	public String name;
	V_one(){}
	V_one(String str){name = str;}
}

class V_two{
	public String name;
	V_two(){}
	V_two(String str){name = str;}
	
	public Boolean equals(V_two v) {
		return name.equals(v.name);
	}
}
public class OverWriteEquals {
	public static void main(String[] args) {
		String str1 = new String("123");
		String str2 = new String("123");
		
		V_one one1 = new V_one("ab");
		V_one one2 = new V_one("ab");
		
		V_two two1 = new V_two("cd");
		V_two two2 = new V_two("cd");
		
		System.out.println(str1.equals(str2));    //true
		System.out.println(one1.equals(one2));    //false
		System.out.println(two1.equals(two2));    //true,因为调用了重写的equals()方法
	}
}

三、对象类型的转换

向上转型(将子类对象视为父类对象,自动)。子类对象都可以被看作是一个父类对象。

向下转型,往往会报错,要显式类型转换。在执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常。

四、使用instanceof操作符判断对象类型

就像上面说的,此时,就要在执行向下转型之前,要习惯判断父类对象是否为子类对象的实例。

可以使用instanceof操作符判断是否一个类实现了某个接口(接口在后文),也可以用它来判断一个实例对象是否属于一个类。

myobject instanceof ExampleClass

myobject:某类的对象引用

ExampleClass:某个类

返回值为布尔值

class AA{
    //……
}
class BB extends AA{
    //……
}
class CC{
    //……
}
public class DD extends AA{
    public static voiid main(String[] args){
        AA a = new AA();

        if(a instanceof DD){
            DD d = (DD)a;    //向下转型操作
        }
        if(a instanceof BB){
            BB b = (BB)a;    //向下转型操作
        }
        if(a instanceof CC){    //实例对象a不属于CC类
            //……
        }
    }
}

五、方法的重载

方法的重载在就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。但只有返回类型不同也不行,还需要通过参数以及参数的类型来设置。(常规略)

定义不定长参数方法

不定长方法语法:

返回值 方法名(参数数据类型 ...参数名称)    //3个英文句号
public class UncertainLengthAdd {
	public static int add(int...a) {
		int sum = 0;
		for(int i=0;i<a.length;i++) {
			sum += a[i];
		}
		return sum;
	}
	public static void main(String[] args) {
		System.out.println(add(1,2,3));    //6
		System.out.println(add(1,2,3,4,5,6));    //21
	}
}

六、多态

如果定义一个四边形类,让它处理所有继承该类的对象,根据”向上转型“原则可以使每个继承四边形类的对象作为draw()方法的参数,然后再draw()方法中作一些限定就可以根据不同图形类对象绘制相应的图形,从而以更为通用的四边形类来取代具体的正方形类和平行四边形类。这样处理就能够很好地解决代码冗余的问题,同时也易于维护。使得无需在所有子类中定义执行相同功能的方法。

在多态机制中,并不需要将弗雷初始化对象,需要的只是子类对象。会把子类对象都向上转型为父类对象来调用父类方法。

创建Quadrangle类,再分别创建两个内部类Square和Parallelogramgle,它们都继承了Quadrangle类。编写draw()方法,该方法接受Quadrangle类的对象作为参数,即使用这两个内部类的父类作为方法参数。在住方法中分别以两个内部类的实例对象作为参数执行draw()方法。

//定义一个正方形类,继承四边形类
class Square extends Quadrangle{
	public Square() {
		System.out.println("正方形");
	}
}
//定义一个平行四边形类,继承四边形类
class Parallelogramgle extends Quadrangle{
	public Parallelogramgle() {
		System.out.println("平行四边形");
	}
}
public class Quadrangle {
	//实例化保存四边形对象的数组对象
	private Quadrangle[] qtest = new Quadrangle[6];
	private int nextIndex = 0;
	public void draw(Quadrangle q) {
		if(nextIndex<qtest.length) {
			qtest[nextIndex] = q;
			System.out.println(nextIndex);
			nextIndex++;
		}
	}
	public static void main(String[] args) {
		//实例化两个四边形对象,用于调用draw()方法
			Quadrangle q = new Quadrangle();
			q.draw(new Square()); 		//以正方形对象为参数调用draw()方法
			q.draw(new Parallelogramgle());		//以平行四边形对象为参数调用draw()方法
	}
}

结果为:

七、抽象类与接口

1、抽象类

一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。在多态机制中,并不需要将父类初始化对象,需要的只是子类对象。所以java中,抽象类不可以实例化对象,其子类可以。

抽象类语法:------抽象类关键字abstract

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

1、使用absract关键自定义的类称为抽象类,使用这个关键字定义的方法称为抽象方法。

2、抽象方法没有方法体。抽象方法只能定义在抽象类中。

3、承载抽象方法的抽象类必须被继承。

4、继承抽象类的所有子类必须重写抽象类中的所有抽象方法。保证相同的方法名称、参数列表和相同返回值类型。子类可以创建出非抽象方法,或者抽象方法。

---->当子类中的一部分需要一个方法,而另一部分不需要这一方法时(如果在父类抽象类中定义该方法,那么不需要这个方法的子类也必须重写该方法)

---->解决方法:接口

2. 接口

1、接口是抽象类的延伸,可看作纯粹的抽象类。

2、接口中所有方法都没有方法体。

3、可将上述(一部分子类需要一部分不需要的)方法封装到一个接口中,使需要这些方法的那一部分类实现该接口,同时所有类都继承父类抽象类。

4、接口使用interface关键字进行定义:

public interface drawTest{
    void draw();    //接口内的方法,省略abstract关键字
}

5、一个类实现一个接口可以使用implements关键字:

public class 子类名 extends 父类抽象类名 implements 接口名{
    ……//
}

6、在接口中定义的方法必须被定义为 public 或 abstract 形式,其他修饰权限不被java编译器认可。即使不将该方法声明为public形式,它也是public。

7、在接口中定义的任何字段都自动是 static 和 final 的。

3. 接口与继承

Java中不允许多重继承,即不允许一个子类同时继承一个或多个父类(即同时extends多个类)。

实现方法:使用接口可以实现多重继承(即可以同时implements多个接口,同时实现多个接口)。

多重继承语法:

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

在定义一个接口时使该接口继承另外一个接口:

interface intf1{
    ...//
}
interface intf2 extends intf1{
    ...//
}

1、一个类只能继承一个类:class A extends B{}

2、一个类可以实现多个接口:class A implements B,C,...{}

3、一个接口可以继承多个接口:interface intf1 extends intf2,intf3,...{}

4、在继承类的同时也可以继承接口:class A extends B implements intf1,intf2,...{}

这就是选择用接口而不选择抽象类的原因。

(具体代码示例:)

interface drawTest{		//定义接口
	public void draw();		//定义方法,没有方法体
}
class ParallelogramgleUseInterface extends QuadrangleUseInterface implements drawTest{
	public void draw() {		//因为该类实现了接口,所以需要覆盖draw()方法
		System.out.println("平行四边形.draw()");
	}
	public void doAnything() {		//覆盖父类方法
		//……
	}
}
class SquareUseInterface extends QuadrangleUseInterface implements drawTest{
	public void draw() {
		System.out.println("正方形.draw()");
	}
	public void doAnything() {
			//……	
	}
}
public class QuadrangleUseInterface {
	public void doAnything() {
		//……
	}
	public static void main(String[] args) {
		//接口也可以进行向上转型操作
		drawTest[] d = {new SquareUseInterface(), new ParallelogramgleUseInterface()};
		for(int i=0;i<d.length;i++) {
			d[i].draw();		//调用draw()方法
		}
	}
}

结果为:

猜你喜欢

转载自blog.csdn.net/qq_42182367/article/details/82111312