【Java基础】(十一)面向对象的三大特性

本文详细介绍了Java编程中的面向对象特性,包括封装性、继承和多态。封装性强调隐藏实现细节,通过访问修饰符控制属性和方法的可见性。继承允许子类继承父类的属性和方法,子类可以重写父类方法以实现自定义行为。多态则是子类对象可以表现出不同的形态,允许父类引用指向子类对象,提供了编译时和运行时的灵活性。文章通过实例代码展示了如何在Java中实现这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


面向对象的三大特性,分别为:封装、继承、多态。

一、封装性

1. 封装性概念

简言之就是隐藏该隐藏的,暴露该暴露的。

一般情况下,我们将我们类中的属性设为private,方法设为public。并为private属性提供set和get方法。

事实上,对象的出现就是为了封装数据的,每个对象都封装自己的数据。

2. 修饰符的范围

修饰符的范围可见下表:
在这里插入图片描述

3. static修饰符

如果说,封装性是我们每个对象自私、独享的一面,那么static便是对象无私、共享的一面。
static可以修饰类中的属性和方法。被static修饰的属性和方法,是所有该类的对象所共享的。这个共享表现在两个方面:

  1. 被static修饰的属性的值,在所有变量中共享,也就是说,你改变一个对象中的static属性时,其他的对象中的该属性值也会随着改变。
  2. 即使在还没有创建该类的对象时,就可以通过类名.属性名,或类名.方法名()的方式访问static修饰类的属性。也正是因为这样,static类型的方法只能访问static类型的属性,因为在对象还未创建时,非static类型的属性还不存在。

正是因为static修饰的方法可以在没有类对象的时候被执行,所以我们的main方法需要被static修饰。

新建一个Person类,添加static类型的属性(并创建其set、get方法)和方法:

package com.daw.test2;

public class Person {
	private String id;
	private String name;
	private int age;
	//static修饰变量
	static String nation;
	
	//static修饰方法
	public static void test() {
		System.out.println(nation);
		//System.out.println(id);	//static的方法只能访问static的对象
	}
	
	//方法
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	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 String getNation() {
		return nation;
	}
	public void setNation(String nation) {
		this.nation = nation;
	}
}

编写类Test2来尝试访问static修饰的对象和方法

package com.daw.test2;

public class Test2 {

	public static void main(String[] args) {
		//在未创建Person类的对象时,即可访问static修饰的属性
		Person.nation = "中国";
		System.out.println(Person.nation);
		Person.test();
		System.out.println("******************");
		
		Person p1 = new Person();
		Person p2 = new Person();
		System.out.println(p1.nation);	//nation不再是private类型变量,可以外部直接访问
		System.out.println(p2.nation);
		
		System.out.println("******************");
		p2.nation = "中华人民共和国";
		System.out.println(Person.nation);
		System.out.println(p1.nation);
		System.out.println(p2.nation);
		
		System.out.println("******************");
	}

}

可见,当修改了p2中的nation属性值以后,类和p1的也跟着改变了。

二、继承

1. 什么是继承

比如我们人,是一种动物,具有动物的所有特征和特性;轿车是汽车,大巴也是汽车,它们也都具有汽车的所有特征。在Java中,我们将这种关系称之为继承。
定义:继承就是子类继承父类的特征(属性)和行为(方法),使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

我们现在只需要知道,父类是原有的,子类是在父类基础上的延伸,至于上一句话什么意思,通过代码来学习。

2. 子类对象继承父类对象的全部属性和方法。

我们新建一个包,再其中创建一个类Animal,使之具有 属性age 和 方法sleep。

package com.daw.test3;

public class Animal {
	
	int age;
	
	public void sleep() {
		System.out.println("休息。。。");
	}
	
}

假如我们需要定义一个类person,它包含Animal所具有的的所有的属性和方法,那么我们就可以让它继承Animal。

事实上,java中使用的是extend,翻译为扩张,比起继承,显然扩张更符合这个功能的原本含义。BUT…

想要让一个类继承另一个类,有两种办法。

1)继承方法一:在创建类时使其继承另一个类

在我们创建类时,有Superclass一项,此项为选择所创建类的父类,我们点击后面的Browse,或者手动写上我们的所要继承的类的 包名.类名。
在这里插入图片描述
在弹出的界面输入我们要继承的类名,并选择我们要继承的类(注意后面的包名要对应)。
在这里插入图片描述
完成创建以后,我们便成功继承了的Animal类。
在这里插入图片描述

2)继承方法二:在创建类以后手动添加extend

由上面最终创建的Person类,很多人会发现,不就是多了一个extends Animal吗,直接手动写上岂不是更加更方便。其实是可以的。
但是需要注意:

  1. 父类和子类在同一个包中,可以直接写extends 父类
  2. 父类和子类不在同一个包中,例如,我希望我的Person类继承我们之前的com.daw.test2中的Car类。在写完extends Car以后,一定要选择正确的包。
    在这里插入图片描述
    选择完成后,会有import 包名.类名;
    在这里插入图片描述
    我们之前在需要从键盘获取数据时,使用过Scanner,当时也会产生一行import java.util.Scanner;
    在我们的类中,使用其他包中的类中的属性或方法时,我们就需要用import来告诉我们的程序,这些类、属性、方法是从哪里来的。这也是包存在的意义之一。

当然,我们这里让Person继承Car类只是为了补充一部分包的内容,关于包的内容还有很多,我们慢慢的补充。
我们把Person类的继承关系改回Animal。创建新的类Test1来实验一下。

package com.daw.test3;

public class Test1 {

	public static void main(String[] args) {
		Animal animal = new Animal();
		animal.age = 1;
		
		System.out.println(animal.age);
		animal.sleep();
		System.out.println("************");
		
		Person person = new Person();
		person.age = 1;
		System.out.println(person.age);
		person.sleep();
	}

}

运行结果可见,虽然我们并没有给Person类写内容,但是Person类的对象也拥有Animal类的属性和方法。
在这里插入图片描述

3. 子类对象可以通过重写(override,又称覆盖)来自定义父类中的方法。

很多时候,我们在父类中的方法可能并不能满足我们子类的需求,这时候我们就要使用重写。
在Person类中重写sleep方法。

注意:

  1. 在重写方法时,方法名、返回值和参数列表要相同,如果只是方法名相同,返回值和参数列表不同,则为重载,不能加@override。
  2. 重写方法时,可以自己敲,也可以利用鼠标右键-> Source -> Override/Implement Methods来生成我们要重写的方法。
package com.daw.test3;

public class Person extends Animal {

	//重载:不能加@Override
	public void sleep(String name){
		System.out.println(name + "睡觉。。。");
	}
	
	//重写:要加@Override
	@Override
	public void sleep() {
		System.out.println("上床睡觉。。。");
	}
	
}

重写运行Test1。
在这里插入图片描述

4. 子类中可以定义新的属性和方法

在子类中,我们不止可以重写父类中的方法,我们还可以添加新的属性和方法。比如人比起动物,人有名字,可以工作。我们因此给person添加新的属性和方法。

	String name;
	public void work(){
		System.out.println("工作。。。");
	}

我们在Test1中尝试调用person类新加入的属性和方法

	person.name = "五代";
	System.out.println(person.name);
	person.work();

运行后可以成功输出我们的属性,也可以成功运行我们的方法。
在这里插入图片描述

5. 多级继承

我们继承了其他类的类,也可以被继承。比如我们定义一个Student类,使其继承Person类。方法与之前完全相同。此时Animal类,即为Student类的间接父类。

6. Object类和java.lang包

在我们创建类时,发现父类,默认为java.lang.Object。
Object类是java.lang包中的类,是所有类的父类。

注意:

  1. 如果一个类没有指定父类,那么这个类的父类的Object类;
  2. 如果一个类指定了父类,那么这个类的间接父类的Object类;

java.lang包是Java提供给我们的工具包,其中包含了我们java代码中最最基础的一些操作。也正因如此,java.lang包也是唯一不需要导入(import)即可以使用的包。
除了lang包外,java还为我们提供了现成的工具类,比如Scanner所在的java.util等等。我们不需要所有的都掌握,当我们需要某种功能时,我们可以去搜索,一般即可找到对应的类和其使用方法。在需求中学习即可。
大家可以通过搜索器搜索API文档(API 为 应用程序编程接口,指一些预先定义好的类),来查看对应的JDK版本中Java为我们提供的方法及其使用方法。其中在 在线API文档 网站中:

1)左上角---包
2)左下角---包中的类和接口
3)右侧-----类的详细信息
	|-----构造方法 Constructor
	|-----属性 Field
	|-----方法 Method
			|---返回值类型
			|---方法名
			|---参数列表
			|---概要信息

三、多态

1. 什么是多态

学生是人,老师也是人。因此,当我们有一个“人”的对象时,它可以为“老师”,也可以为“学生”,可以表现为多种形态。这就是多态性。
在Java中,我们将子类对象赋值给父类引用父类引用指向子类对象),来实现多态。
列如:

	Person p = new Student();

2. 多态性的特点

  1. 编译时,只能访问左边类(父类)具有的属性和方法
  2. 运行时,方法访问右边类(子类)具有的属性和方法

为了表现出我们的 student类 和 Person类 的不同,在student中添加属性stuId表示学号、添加learn方法,并重写work、sleep方法。

package com.daw.test3;

public class Student extends Person {
	
	String stuId;
	
	public void learn(){
		System.out.println("上课。。。");
	}
	
	@Override
	public void work(){
		System.out.println("写作业。。。");
	}
	
	@Override
	public void sleep(){
		System.out.println("学生睡觉。。。");
	}
	
}

我们新建一个test2来测试一下。首先我们尝试访问student中的属性,发现报错。表明特点一符合,无法使用子类中的属性和方法(方法自习测试)。
在这里插入图片描述
我们再实验特点二,访问其work方法。

package com.daw.test3;

public class Test2 {

	public static void main(String[] args) {
		
		Person person = new Student();
//		person.stuId;	//报错,仅能使用指针所属的类中的属性和方法。

		person.work();
	}

}

输出如下。表明,在运行过程中,访问的是对象所属类中的属性和方法。
在这里插入图片描述

3. instanceof运算符

instanceof用于判断一个类是否属于某种类,返回 boolean类型。

用法:对象 instanceof 类名
	if (person instanceof Student) {
		System.out.println(1);
	}
	if (person instanceof Person) {
		System.out.println(2);
	}

判断结果表明,person既属于student,又属于person(子类对象既属于子类,又属于父类;而父类对象只属于父类。),这也表明了,在运行时,是以实际对象所属的类进行操作的。

4. 多态的转型

  1. 向上转型 -> 通过子类对象实例化父类对象,这种属于自动转换
  2. 向下转型 -> 通过父类对象实例化子类对象,这种属于强制转换

多态就属于向上转型。这种转型是自然的,无条件的。所有的子类对象,都可以被赋值给其父类指针。
而在有些时候,我们需要使用一些子类中特有的属性和方法时,我们就不得不再将这一过程逆回去,也就是向下转型。

注:向下转型的要求为,父类对象实际所属的类,应当为所要转型类的类或其子类

创建一个类Test3。

package com.daw.test3;

public class Test3 {

	public static void main(String[] args) {
		//向上转型
		Animal a = new Student();
		
		//向下转型1 --- 实际对象所属的类为转型类的子类
		Person p = (Person) a;
		p.age = 5;
		System.out.println(a.age);
		System.out.println(p.age);
		p.sleep();
		
		向下转型2 --- 实际对象所属的类为转型类
		Student s = (Student) a;
		s.age = 10;
		System.out.println(p.age);
		System.out.println(s.age);
	}

}

由结果可知,a、p和s的age是同一个,因此,a、p和s是指向同一区域的引用,而非复制出一个新的对象。
在这里插入图片描述

5. 子类对象的多态性的应用

继承于同一父类的对象,可以依靠引用父类,将相似的方法写成一个。而不必以每种类型进行方法的重载。

例如,我们创建一个Teacher类,也继承于Person类,为其添加一个Teach方法。

package com.daw.test3;

public class Teacher extends Person {
	
	public void teach(){
		System.out.println("教课。。。");
	}
}

此时,我们希望在test4完成开始上课这一动作,如果是老师,则执行其teach方法,如果是学生,则执行其learn方法。
如果我们不使用多态,则需要写一个参数为Teacher的方法,再重载一个参数为Studen类型的方法。而使用多态则只需要一个程序即可。

package com.daw.test3;

public class Test4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student s = new Student();
		test(s);
	}
	
	public static void test(Person person) {
		if (person instanceof Teacher) {
			Teacher teacher = (Teacher) person;
			teacher.teach();
		}else if (person instanceof Student) {
			Student student = (Student) person;
			student.learn();
		}
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值