不是吧,都2020年,不会还有人没找到对象吧。
(我们先来回顾一下面向对象程序设计的一些知识点)
首先面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。从根本上说,只要对象能够满足功能,那么就不必关心对象的具体实现。OOP将数据放在第一位,然后再考虑操作数据的算法。
西瓜籽:“既然Java是一门OOP语言,那么对象是从哪里来的呢?”
大西瓜:“类是构造对象的模板,由类构造对象的过程称为创建类的实例。可以说对象是类的实例!”
在类与类之间,最常见的关系有:
下面我们就来具体的了解下它们:
继承,即“is-a”关系,是一种用于表示特殊与一般关系的。关键字 extends ,表明正在构造的新类派生于一个已存在的类,这个类包括现有类型的所有成员(尽管private成员被隐藏了起来,并且不能被访问)。引入父类(超类)和子类两个术语。
下面我们来用Animal类、Bird类、Fish类来说明下:
Animal类:
public class Animal {
private int age;
String name;
public Animal(){
}
public Animal(String name){
this.name=name;
}
public void getName(){
System.out.println("我的名字是:"+name);
}
public String setName(){
return name;
}
void eating(){
System.out.println("我要吃饭");
}
void calling(){
System.out.println("我有叫声");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Bird类:
public class Bird extends Animal {
public Bird(){
super("小鸟");
}
@Override
void calling() {
System.out.println("我的叫声是:啾啾...");
}
void flying(){
System.out.println("我会飞!");
}
}
Fish类:
public class Fish extends Animal {
public Fish(){
super("小鱼");
}
@Override
void calling() {
System.out.println("咕噜咕噜...");
}
void swimming(){
System.out.println("我会游泳!");
}
}
Test测试类:
public static void main(String[] args) {
//鸟
Bird bird = new Bird();
bird.getName();
bird.calling();
bird.flying();
System.out.println();
//鱼
Fish fish = new Fish();
fish.getName();
fish.calling();
fish.swimming();
}
输出结果:
我的名字是:小鸟
我的叫声是:啾啾...
我会飞!
我的名字是:小鱼
我的叫声是:咕噜咕噜...
我会游泳!
往上翻,我们在Animal类中定义了一个private修饰的int age:
private int age;
这里就是为了解释 “这个类包括现有类型的所有成员(尽管private成员被隐藏了起来,并且不能被访问)”,这句话是引用于《Java编程思想第四版》。在一些资料中我们经常可以看到这样一句话“子类拥有父类非 private 的属性、方法。”其实你仔细品一下下面这段代码,你会发现这句话是有些问题的。
bird.setAge(2);
System.out.println("我是小鸟,我已经"+bird.getAge()+"岁了!");
System.out.println("我是小鱼,我已经"+fish.getAge()+"岁了!");
输出结果:
我是小鸟,我已经2岁了!
我是小鱼,我已经0岁了!
通过代码我们发现,其实是可以通过brid对象和fish对象,对age字段进行赋值和取值。而且我们通过bird进行的setAge操作并未对fish对象造成影响,结果是初始状态0。 所以我们不难得出,子类对象其实是拥有父类对象中所有的所有成员的,只是父类对象中的私有属性和方法,子类无法访问而已,只是拥有,但不能使用。 就像有些东西你可能拥有,但是你并不能使用。所以子类对象是绝对大于父类对象的,所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。
西瓜籽:“不对啊,你这里说子类无法访问父类的私有成员啊,那为啥上面那段代码的却有结果?”
大西瓜:“我在Animal类中声明了set/get方法来对私有的age变量来进行操作。”
西瓜籽:“子类并没有可使用的age啊,你这不是在对父类Animal进行操作吗?”
大西瓜:“看来你还是不能理解 子类拥有父类所有成员 这句话啊,我再给你掰扯一下,子类在创建的时候会把父类里的成员变量和方法也加载进内存,也就是说在子类的内存中是有age的,我们就可以通过set/get方法对age进行操作。然后用this和super这两个引用来区分是父类的还是子类的,但是这个内存区域是子类的内存区域。this范围大于等于super。还有就是,因为父类数据要加载进子类内存,所以创建子类时会先调用父类的构造函数,来对这些数据进行相应的初始化操作。要注意的是,这里的调用父类构造函数可不是创建一个父类对象啊,真的就只是执行了构造函数,但是内存中并未new一个父类对象。”
西瓜籽:“原来是这样啊!我懂了,大西瓜真菜!”
大西瓜:“我xx你个xx...”
“为新的类提供方法”并不是继承技术中最重要的方面,其最重要的方面是用来表现新类和基类之间的关系。这种关系可以用“新类是现有类的一种类型”这句话加以概括。——《Java编程思想第四版》
既然讲到继承了,当然要来聊一下向上转型和向下转型(不被编译器允许)
//这里使用的是Junit5进行测试
@org.junit.jupiter.api.Test
public void test(){
Animal animal = new Bird();
animal.getName();
animal.calling();
//annimal无flying()方法
//animal.flying();
}
输出结果:
我的名字是:小鸟
我的叫声是:啾啾...
向上转型:将一个子类的引用赋给一个超类变量,即父类的对象引用指向子类对象。可以理解为小范围指向大范围,这是被编译器所允许的。annimal对象无flying()方法,说明向上转型时,父类只能调用父类方法或者子类覆写后的方法,而子类中的单独方法则是无法调用的。
向下转型:与向上转型相反,将一个超类的引用赋给一个子类变量,即子类的对象引用指向父类对象。这时就是大范围指向小范围了,只是不被编译器允许的。
依赖,即"uses-a"关系,是一种最明显、最常见的关系。即一个类的实现需要依赖于另一个类。属于弱关联关系。
我们用学生需要英语老师,教英语来说明该关系。
Student类:
public class Student {
public Student(){};
//使用形参方式发生依赖关系,还可以使用局部变量和静态变量方式
public void learn(Teacher teacher){
System.out.println("我需要"+teacher.getSubject()+"老师,"+teacher.teaching());
}
}
Teacher类:
public class Teacher {
private String subject;
public Teacher(){}
public Teacher(String subject){
this.subject=subject;
}
public String teaching(){
return "教我"+subject;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
Test测试类:
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.learn(new Teacher("英语"));
}
}
输出结果:我需要英语老师,教我英语
注意:我们在实际开发的时候应尽可能的减少这种关系的使用,以降低耦合度。
聚合,即“has-a”关系,是一种具体且易于理解的关系。聚合关系意味着类A的对象包含类B的对>象。属于强关联关系。
这时我们只需要改动下依赖关系中的Student类和Test测试类就可以实现这种关系。
Student类:
public class Student {
public Student(){};
//添加一个构造方法,用来初始化teacher
public Student(Teacher teacher){
this.teacher=teacher;
};
Teacher teacher;
public void learn(){
System.out.println("我需要"+teacher.getSubject()+"老师,"+teacher.teaching());
}
}
Test测试类:
public class Test {
public static void main(String[] args) {
Teacher teacher = new Teacher("英语");
Student student = new Student(teacher);
student.learn();
}
}
输出结果:
我需要英语老师,教我英语
注意:我们在实际开发的时候更应尽可能的减少这种关系的使用,以降低耦合度。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有