Java学习笔记10

Java学习——Java面向对象04(面向对象高级 下)


一、抽象类与抽象方法

(1). 抽象类

概念:在Java中具有抽象方法的类称为“抽象类”。

在Java中抽象类和抽象方法的修饰符是 abstract ,抽象类必须使用abstract class 声明一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。

抽象类是一种没有完全实现的类。不能用它实例化任何对象,,它的主要用途是用来描述一些钙奶女性的内容,然后再子类中具体实现这些概念,这样可以提高开发效率,统一用户接口,所所以抽象类更多是作为其他类的父类。

格式:

// 抽象类
abstract class 类名{ 
 }

(2). 抽象方法

概念:只声明而未实现的方法称为抽象方法(未实现指的是:没有“ { }方法体 ),抽象方法必须使用 abstract 关键字声明。

格式:

// 抽象类 
abstract class 类名{ 
public abstract void 方法名() ; 	// 抽象方法,只声明而未实现 
}

注意事项:

  • 抽象类本身是不能直接进行实例化操作的,即:不能直接使用关键字new完成。

  • 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须覆写(重写)抽象类中的全部抽象方法。如果一个抽象类没有被继承,那么这个抽象类被定义出来就没有意义。

  • 抽象类不能使用 final 声明,因为 final 属修饰的类是不能有子类的 , 而抽象类必须有子类才有意义,所以不能。

  • 抽象类是能有构造方法的,而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。

抽象类和普通类的区别:

  1. 抽象类必须用 publicprotected 修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。 默认缺省为 public
  2. 抽象类不可以使用 new 关键字创建对象, 但是在子类创建对象时, 抽象父类也会被 JVM 实例化。
  3. 如果一个子类继承抽象类,那么必须实现其所有的抽象方法如果有未实现的抽象方法,那么子类也必须定义为 abstract类

举例:

//抽象类Fruit
public abstract class Fruit {
	public void say() {
		System.out.println("This is fruit!");
	}
	
	//抽象方法 abstract修饰
	public abstract void kinds();
}

创建一个Apple类继承它

//Apple类
public class Apple extends Fruit{

	public static void main(String[] args) {
		// f变量是父类类型,指向子类实例,发生多态
		Fruit f = new Apple();
		f.say();
		f.kinds();
	}

	//父类抽象方法的重写
	@Override
	public void kinds() {
		System.out.println("And I'm a Apple!");
	}
}

运行结果:
继承抽象类会报错,显示需要添加未实现的抽象方法
在这里插入图片描述
在这里插入图片描述

二、接口

概念:
比抽象类更加抽象的是接口,在接口中所有的方法都是抽象的,全部属性都是全局常量。

(1). 接口定义

格式:

interface 接口名称{ 
全局常量 ; 
抽象方法 ; 
}

(2). 接口实现

由接口生成子类不是通过 extends 实现的,而是使用关键字 implements 来实现一个接口。
接口可以多实现,接口名之间使用逗号隔开。
格式:

class 子类 implements 父接口1,父接口2...
{ 
}

当一个类即要实现接口,又要继承抽象类的话,按照以下格式实现:

class 子类 extends 父类 implements 父接口1,父接口2...{ 

}

接口因为都是抽象部分,不存在具体的实现,所以允许多继承,格式如下:

interface C extends A,B{

 }

如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法。


接口和抽象类的区别:

  1. 抽象类要被子类继承,接口要被类实现。
  2. 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
  3. 接口里定义的变量只能是公共的静态的常量,抽象类中的变量可以是普通变量(接口中的变量定义默认为公共静态)。
  4. 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
  5. 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
  6. 接口不能有构造方法,但是抽象类可以有

举例:

Food 接口类:

public interface Food {
	//可以看到定义的变量 a 与 num 均为加粗斜体显示,表示a 与num 均为公共静态常量
	//不过num定义出来,前面的修饰符系统是默认给出的
	public static final int a = 10;
	int num = 10;
	
	void say();
}

Pear类实现接口:

public class Pear implements Food{
	public static void main(String[] args) {
		Food f = new Pear();
		f.say();
		System.out.println(f.num);
}
	
	@Override
	public void say() {
		System.out.println("I'm a Pear!");
	}
}

运行结果:
在这里插入图片描述


三、Object类

概念:
Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object类。

例如,我们定义一个类:

public class Person{ }

其实它被使用时,是这样的:

 public class Person extends Object{ }

使用Object可以接收任意的引用数据类型
比如任意一种数据类型的数据传入,我们这时可以用 Object 来接收

接下来了解一下Object类中的 toStringequals 方法。

(1). toString

建议重写Object中的toString方法。 

此方法的作用:返回 对象 的字符串表示形式。
Object的 toString 方法, 返回对象的内存地址。

举例:

首先先创建一个具构造方法,具set/get方法普通的Person类:

public class Person {
	public String name;
	public int age;
	
	
	//构造方法
	public Person(){
	}
	
	public Person(String name,int age) {
		System.out.println("Person类被创建!");
		this.name = name;
		this.age = age;
	}
	
	//属性的获得与赋值方法
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public void show() {
		System.out.println("这是个人,姓名:" + name + ",年龄为:" + age);
	}

}

创建一个Demo1 测试:

public class Demo1 {
	public static void main(String[] args) {
		Person p1 =new Person();
		Person p2 =new Person();
				
		System.out.println(p1.toString());
	}
}

运行结果:
在这里插入图片描述
我们跳到toString方法界面,可以看到toString方法输出内容:
输出内容的第一项是 该对象对应的那个类所在地址:test.Person
在这里插入图片描述
我们便是建议取重写toString方法:
在Person类中重写出 我们想要在控制台输出的内容。
在Person类添加一下代码:

public String toString() {
	return "This is a Person! ,姓名为:" + this.name + ",年龄为:" + this.age;
}

返回Demo1,运行结果:
在这里插入图片描述

重写toString方法是为了调用该方法,输出我们想要的结果。

(2). equals

建议重写Object中的equals(Object obj)方法。

此方法的作用:指示某个其他对象是否“等于”此对象。
Object的 equals 方法:实现了对象上最 具区别的可能等价关系 ;
也就是说,对于任何非空引用值x和y ,当且仅当 x和y引用同一对象( x == y具有值true )时,此方法返回true 。

举例,沿用上面的Person类,我们将Demo1修改如下:

public class Demo1 {
	public static void main(String[] args) {
		Person p1 =new Person();
		Person p2 =new Person();
		
		p1.setName("王二");
		p1.setAge(18);
		p1.setName("王二");
		p1.setAge(18);
		
		System.out.println(p1.equals(p2));
	}
}

运行结果:
在这里插入图片描述
我们跳到 equals 方法,该方法中的 == 就是比较两个对象的内存地址是否相同。
在这里插入图片描述
而我们调用 equals 方法是想要比较两个对象中某些属性是否一致,如果一致,我们便认为两个对象相同。

在Person类中,添加equals方法的重写:

public boolean equals(Object obj) {
	if(this == obj) {	//如果这两个对象都相同了,那必然一样
		return true;
	}
	if(obj == null) {	//比较对象为空时
		return false;
	}
	if(obj instanceof Person) {	//如果比较对象是Person类
		Person p = (Person) obj;		//将比较对象转换为Person类
		if(this.name.equals(p.name) && this.age == p.age) {
			return true;
		}
	}
	return false;	//均不成立	
}

此时再次运行Demo1时,得到我们想要的比较结果(当两个对象的姓名和年龄相等时,我们认为两对象相同):
在这里插入图片描述
equals方法重写时的五个特性:

  • 自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
  • 对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
  • 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后
    x.equals(z)应该返回true 。
  • 一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象
    上的equals比较中使用的信息。
  • 非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。

对于上面重写 toStringequals 方法,eclipse给我们有提供快速生成方法:
使用eclipse快捷键 shift + alt + s ,跳出一下界面:
在这里插入图片描述
点击要重写的equals 或者 toString 方法 , 勾选所想要比较的属性:
在这里插入图片描述

系统生成与我们自己重写的相比较(被注释的为我们重写的):
在这里插入图片描述
生成 toString 方法与上同

总结

高级面向对象方法(下),( ̄︶ ̄)↗ !!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值