第七章总结

类的继承

继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性。在程序中复用一些已经定义完善的类,不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性。

在Java语言中,一个类继承另一个类需要使用关键字extends,关键字extends的使用方法如下:

class Child extends Parent{}

因为Java只支持单继承,即一个类只能有一个父类,所以类似下面的代码是错误的:

class Child extends Parent1,Parent2{}

子类在继承父类之后,创建子类对象的同时也会调用父类的构造方法。

【例题7.1】

package Seven;

class Parent{
public Parent(){
		System.out.println("调用父类构造方法");
		}
}
class Child extends Parent{
public Child(){
		System.out.println("调用子类构造方法");
	}
}
public class Demo {
public static void main(String[]ages){
		new Child();
}

}

运行结果及代码截图如下:

 子类继承父类之后可以调用父类创建好的属性和方法

【例题7.2】

package Seven;

class Telephone{//电话类
String button="button:0~9";//成员属性,10个按键
void call(){//拨打电话功能
System.out.println("开始拨打电话");
}
}
class Mobile extends Telephone{//手机类继承电话类
String screen="screen:液晶屏";//成员属性,液晶屏幕
}
public class Demo2{
public static void main (String[]args){
Mobile motto=new Mobile();
System.out.println(motto.button);//子类调用父类属性
System.out.println(motto.screen);//子类调用父类没有的属性
motto.call();//子类调用父类方法
}
}

 子类Mobile类仅创建了显示屏属性,剩余的其他属性和方法都是从父类Telephone类中继承的。

Java虽然不允许同时继承两个父类,但不代表没有多继承的关系,可以通过类似“祖父>父亲>儿子>孙子”的方式实现多带继承。

例如,绝大多数动物有眼睛、鼻子和嘴,犬类也有眼睛、鼻子和嘴。哈士奇是犬类的一个品种,犬类有的特性哈士奇都有。但哈士奇的眼睛、鼻子和嘴并不是从犬类继承的而是从动物类继承的。用Java的编码如下:

class Animal{//父类:动物类
Eye eye;
Mouth mouth;
Nose nose;
}
class Dog extends Animal{}//子类:犬类
class Husky extends Dog{}//孙子类:哈士奇类

这三个类的继承关系就是Husky类继承Dog类继承Animal类,虽然Husky类没有直接继承Animal类,但是Husky类可以调用Animal类提供的可被继承的成员变量和方法。

Object类

开始学习使用class关键字定义类时,就应用到了继承原理,因为在Java中所有的类都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是Java类层中的最高层类。用户创建一个类时,除非已经指定要从其他类继承,否则它就是从java.lang.Object类继承而来的。Inreger类等都是继承于Object类。除此之外,自定义的类也都继承于Object。由于所有的类都是Object类的子类,所以在定义类时可以省略extends Object。

由于所有的类都是Object的子类,所以所有的类都是Object类的子类,所以任何类都可以重写Object中的方法。

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

下面详细讲述Object类中的几个重要方法。

1.getClass()方法

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

getClass().getname();

2.toString()方法

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

【例题7.3】让学生自我介绍

package Seven;

public class Student {
	String name;
	int age;
	
	public Student(String name,int age) {
		this.name=name;
		this.age=age;
	}
	public String toString() {
		return "我叫"+name+",今年"+age+"岁";
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student s1=new Student("张三",16);
		System.out.println(s1);
		Student s2=new Student("李四",19);
		System.out.println(s2);
		

	}

}

代码及输出结果如下图:

 3.equals()方法

在Java语言中,有两种比较对象的方法,分别为“==”运算符与equals()方法。两者的区别在于:“==”比较的是两个对象引用内存地址是否相等,而equals()方法比较的是两个对象的实际内容。

【例题7.4】根据身份证号判断是否为同一人

package Seven;

public class People {
int id;//身份证号
String name;//名字
public People(int id,String name) {
	this.id=id;
	this.name=name;
}
public boolean equals(Object obj) {//重写Object类的equals()方法
	if(this==obj)
		return true;
	if(obj==null)//如果参数是null
		return false;
	if(getClass()!=obj.getClass())//如果参数类型与本类类型不同
		return false;
	People other=(People)obj;//参数强转成本类对象
	if(id!=other.id)//如果两者身份证号不相等
		return true;
	return false;
}
public String toString() {//重写Object的toString方法
	return name;//只输出名字
}
	public static void main(String[] args) {
		People p1=new People(220,"tom");
		People p2=new People(220,"汤姆");
		People p3=new People(330,"张三");
		Object o=new Object();
		System.out.println(p1+"与"+p2+"是否为同一人?");
		System.out.println("equals()方法的结果:"+p1.equals(p2));
		System.out.println("==运算符的结果:"+(p1==p2));
		System.out.println();
		System.out.println(p1+"与"+p3+"是否为同一人?");
		System.out.println(p1.equals(p3));
		

	}

}

运行结果及代码截图如下:

子类重写父类的方法

返回参数相同 方法名相同 传入参数相同 只有方法体不同

传入参数不注重顺序,注重类型!

转型

向上转型:将子类类型的对象转换为父类类型的对象。即把子类对象直接赋值给父类类型的对象。

自动类型转换

Animal a=new Dog();

向下转型:将父类类型的对象转换为子类类型的对象。将父类对象赋值给子类引用。

强制类型转换

Dog a=(Dog)new Animal();

【例题7.5】tom是谁?

使用向上转型模拟如下场景:这里有一个人,他叫tom,他是一名教师

package Seven;
class People1{}
class Teacher extends People1{}

public class Demo3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
People1 tom=new Teacher();
	}

}

因为人类(people)是教师类(Teacher)的父类,所以通过向上转型,能够把教师类型的对象(new Teacher();)直接赋值给人类(People)类型的变量(tom)。进行向上转型,父类类型的对象而可以引用子类类型的对象。而且,向上转型是安全的。

【例题7.6】谁是鸽子?

编写代码证明“可以说某只鸽子是一只鸟,却不能说某只鸟是一只鸽子”:鸟类是鸽子类的父类,用Bird表示鸟类,pigeon表示鸽子类。

package Seven;
class Bird{}
class Pigeon extends Bird{}

public class Sevensix {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Bird bird=new Pigeon();//某只鸽子是一只鸟
		Pigeon pigeon=bird;//某只鸟是一只鸽子

	}

}

报错:Type mismatch: cannot convert from Bird to Pigeon

翻译:类型不匹配

截图:

解决方法:强制类型转换

向下转型语法:

子类类型 子类对象 =(子类对象)父类对象;

package Seven;
class Bird{}
class Pigeon extends Bird{}

public class Sevensix {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Bird bird=new Pigeon();
		Pigeon pigeon=(Pigeon)bird;

	}

}

 截图:

注意:(1)两个没有继承关系的对象不可以进行向上转型或者向下转型

(2)父类对象可以强制转换为子类对象,但有一个前提:这个父类对象要先引用这个子类对象。

重载 

方法名相同 参数不同即为重载

一:返回参数不同

二:传入参数不同

三:传入参数顺序不同

四:传入参数数量不同

顺序不同,也叫重载

【例题7.8】编写不同形式的加法运算方法

package Seven;


public class OverLoadTest {
	public static int add(int a,int b) {//定义一个方法
		return a+b;
	}
	public static double add(double a,double b) {//与第一个方法名相同、参数类型不同
		return a+b;
	}
	public static int add(int a) {//与第一个方法参数个数不同
		return a;
	}
	public static int add(int a,double b) {//先int参数,后double参数
		return a;//输出int参数值
	}
	public static int add(double a,int b) {
		return b;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
System.out.println("调用add(int,int)方法:"+add(1,2));
System.out.println("调用add(double,double)方法:"+add(2.1,3.3));
System.out.println("调用add(int)方法:"+add(1));
System.out.println("调用add(int,double)方法:"+add(5,8.0));
System.out.println("调用add(double,int)方法:"+add(5.0,8));
	}

}

代码截图如下:

 总结:参数类型不同,参数顺序不同,参数个数不同都构成重载

不定长参数方法:

返回值 方法名 (参数数据类型...参数名称)

【例题7.9】使用不定长参数重载加法运算方法

package Seven;


public class OverLoadTest2 {
	public static int add(int a,int b) {
		return a+b;
	}
	public static double add(double a,double b) {
		return a+b;
	}
	public static int add(int a) {
		return a;
	}
	public static int add(int a,double b) {
		return a;
	}
	public static int add(double a,int b) {
		return b;
	}
	public static int add(int ...a) {//定义不定长参数方法
		int s=0;
		for(int i=0;i<a.length;i++) {//根据参数个数做循环操作
			s+=a[i];//将每个参数累加
		}
		return s;//将计算结果返回
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("调用add(int,int)方法:"+add(1,2));
		System.out.println("调用add(double,double)方法:"+add(2.1,3.3));
		System.out.println("调用add(int)方法:"+add(1));
		System.out.println("调用add(int,double)方法:"+add(5,8.0));
		System.out.println("调用add(double,int)方法:"+add(5.0,8));
			
	//调用不定长参数放法
	System.out.println("调用不定长方法:"+add(1,2,3,4,5,6,7,8,9));
	System.out.println("调用不定长方法:"+add(1));
	}
}

运行结果及截图如下:

final

final修饰变量——常量

final修饰方法——该方法不可以被重写

final修饰类——不可以被继承

package Seven;

public class FinalData {
	static final double PI=3.1415926;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("圆周率的值为:"+PI);
		System.out.println("半径为·3的圆的周长为:"+(2*3*PI));
//尝试修改PI的值
		PI=3.1415927;
	}

}
package Seven;


class Dad {
	public final void trunOnTheTv() {
	System.out.println("爸爸打开了电视");
	}
	}
	class Baby extends Dad{
			public final void trunOnTheTv() {
			System.out.println("宝宝也要打开电视");
			}
}

如上述代码则报错:Cannot override the final method from Dad

翻译:无法覆盖爸爸的最终方法

截图如下:

instanceof关键字

用于判断父类对象是否为子类对象的实例。还可以判断一个类是否实现了某个接口

【例题7.7】分析几何图形之间的继承关系

package Seven;
class Quedrangle{}//四边形类
class Square extends Quedrangle{}//正方形类继承四边形类
class Circular{};

public class Demo5 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Quedrangle q=new Quedrangle();//四边形对象
		Square s=new Square();//正方形对象
		System.out.println(q instanceof Square);//判断四边形是否为正方形的子类
		System.out.println(s instanceof Quedrangle);//判断正方形是否为四边形的子类
		System.out.println(q instanceof Circular);//判断正方形是否为圆形的子类

	}

}

因为无法判断正方形为圆形的子类所以报错:Incompatible conditional operand types Quedrangle and Circular

翻译:不兼容的条件操作数类型 Quedrangle 和 Circular

去除最后一行代码,代码截图如下:

多态

利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。

【例题7.12】

package six;
class Shape{}//图形类
class Square extends Shape{}//正方形继承图形类
class Circular extends Shape{}//圆形类继承图形类
public class Demo6 {
	public static void draw(Shape s) {//绘制方法
		if(s instanceof Square) {//如果是正方形
			System.out.println("绘制正方形");
		}
		else if(s instanceof Circular) {//如果是圆形
			System.out.println("绘制图形");
		}
		else {//如果是其他图形
			System.out.println("绘制父类图形");
		}
		
	}

	public static void main(String[] args) {
		draw(new Shape());//调用draw方法判断Shape为什么图形
		draw(new Square());
		draw(new Circular());


	}

}

代码及截图如下: 

类名 insanceof 接口名

判断该类是否实现了该接口

【例题7.13】

package Seven;
interface Paintable{//可绘制接口
	public void draw();//绘制抽象方法
}
class Quadrangle{//四边形类
	public void doAnything() {
		System.out.println("四边形提供的方法");
		
	}
}
//平行四边形类,继承四边形类,并实现了可绘制接口
class Parallelogram extends Quadrangle implements Paintable{
	public void draw() {//由于该类实现了接口,所以需要覆盖draw方法
		System.out.println("绘制平行四边形");
	}
}
//正方形继承平行四边形,并实现了可绘制接口
class Squareab extends Quadrangle implements Paintable{
	public void draw() {
		System.out.println("绘制正方形");
	}
}
//圆形类,仅实现可绘制接口
class Circularab implements Paintable{//圆形类实现接口
	public void draw() {
		System.out.println("绘制圆形");
	}
}
public class Demo7 {

	public static void main(String[] args) {
		Squareab q=new Squareab();//正方形对象
		q.draw();
		q.doAnything();
		Parallelogram p=new Parallelogram();//平行四边形对象
		p.draw();
		p.doAnything();
		Circularab c=new Circularab();//圆形对象
		c.draw();

	}

}

代码及输出截图如下:

 从这个结果可以看出,“绘制”这个行为不是四边形独有的,圆形也能绘制,所有draw()方法被独立封装在了可绘制接口中。

正方形类与平行四边形类分别继承了四边形类并实现了可绘制接口,所以正方形类与平行四边形类既可以调用绘制方法,又可以调用四边形提供的do Anything()方法。但是圆形不属于四边形,且可以绘制,所以最后圆形对象只调用了draw()方法。

抽象类与接口

在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。回想继承和多态原理,继承树中越是在上方的类越抽象,如鸽子类继承鸟类、鸟类继承动物类等。在多态机制中,并不需要父类初始化为对象,我们需要的只是子类对象,所以在Java语言中设置抽象类不可以实例化对象。

使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承没有任何意义。

定义抽象方法:

修饰符 abstract 返回参数 方法名(传入参数);

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

反过来讲,如果声明一个抽象方法,就必须承载这个抽象方法的定义为抽象类,不能在抽象类中获取抽象方法。换句话说,只要类中有一个抽象方法,此类就被标记为抽象类。

抽象类被继承后需要实现其中所有的抽象方法,也就是保证以相同的方法名称、参数列表和返回值类型创建出非抽象方法,当然也可以时抽象方法。

继承抽象类的所有子类需要将抽象类中的抽象方法进行覆盖。这样在多态机制中,就可以将父类修改为抽象类,将draw()方法设置为抽象方法,然后每个子类都会重写这个方法来处理。但这又会出现我们刚探讨多态时讨论的问题,程序中会有太多冗杂的代码,同时这样的父类局限性很大,也许某个不需要draw()的子类也不得不重写draw()方法。如果将draw()方法放置在另外一个类中。让那些需要draw()方法的类继承该类,不需要draw()方法的类继承图形类,又会产生新的问题:所有的子类都需要继承图形类,因为这些类从图形类中导出的,同时某些还需要draw()方法,而Java中规定类不能同时继承多个父类。

有抽象方法的类需要设置为抽象类

修饰符 abstract class 类名{}

抽象方法联合继承:若父类为抽象类,子类要为普通类,那子类必须重写父类所有方法。

接口

重点:因为Java无法实现多继承,可使用接口实现多个接口

接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。因为无法Java无法多继承,所有可以将draw()方法封装到一个接口中,使需要draw()方法的类实现这个接口,同时也继承图形类,这就是接口存在的必要性

接口使用关键字interface关键字进行定义,其语法如下:

public interface Paintable{
void draw();//定义接口方法可省略public abstract关键字
}

public:接口可以像类一样被权限修饰符修饰,但public关键字仅限于接口在与其同名的文件中被定义。

interface:定义接口关键字。

Paintable:接口名

接口  所有对外提供的方法都是抽象方法

修饰符 interface 接口名{}

Java语言每个类可以实现多个接口

一个类继承一个父类同时再实现接口,可以写成如下形式:

public class Paralleogram exrtends Quadrangle implements Paintable{
……
}

注意:(1)在接口中,方法必须被定义为public或abstract形式,其他修饰权限不被Java编译器认可。或者说,即使不将该方法声明为public形式,它也是public形式。

(2)在接口中定义的任何字段都自动是static和final的

实现implements

修饰符 class 类名 inmplements 接口1,接口2……{

}

Java中不允许出现多重继承,但使用接口就可以实现多重继承,一个类可以同时实现多个接口,因此可以将所有需要继承的接口放置在implements关键字后并使用逗号隔开,实现多个接口的语法如下:

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

但这可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法。一个接口可以继承另一个接口,其语法如下:

interface intf{}
interface intf2 extends intf1{}//接口继承接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值