类和类之间的关系
1.子类继承父类,通过一个关键字 extends
2.子类的对象可以调用父类中的(public protected)属性和方法 当做自己的来使用
3.子类可以添加自己独有的属性和方法的
4.子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法 更多指的是内容
5.每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类
可以理解为Object类非常重要 是任何一个引用类型的父类(直接或间接的继承Object) Object类没有父类
6.Java中继承是单个存在的(单继承) 每一个类只能有一个继承类 (在extends关键字后面只能写一个类)
可以通过传递的方式实现多继承的效果 后续还会有多实现
7.继承在内存中的存储形式
8.关于this和super的使用
//父类
public class Animal {
}
//子类,继承了父类Animal
public class Person extends Animal{
}
//基类:Animal 有两个方法一个属性
public class Animal {
public String name;
public void eat(){
System.out.println("动物的吃饭方法");
}
public void sleep(){
System.out.println("动物的睡觉方法");
}
}
基类:Animal 有两个方法一个属性
//子类:Person中什么方法也没有定义,但是继承了父类Animal,所以可以使用父类Animal中的方法。
public class Person extends Animal {
}
子类:Person中什么方法也没有定义,但是继承了父类Animal,所以可以使用父类Animal中的方法。
//主方法,中创建Person类的对象,发现Person类中虽然没有方法和属性,但是Person类的对象可以使用Animal类中函数,因为Person继承了Animal,所以可以使用Animal中的方法和属性。
public class Test {
public static void main(String[] args){
Person p = new Person();
p.name="郑中拓";
p.eat();
p.sleep();
}
}
主方法,中创建Person类的对象,发现Person类中虽然没有方法和属性,但是Person类的对象可以使用Animal类中函数,因为Person继承了Animal,所以可以使用Animal中的方法和属性。
父类Animal中不变
//子类
public class Person extends Animal {
//添加一些独有的属性和方法
public void study(){
System.out.println("good good study,day day up");
}
}
子类Person:添加一些独有的属性和方法
//主方法
public class Test {
public static void main(String[] args){
Person p = new Person();
p.name="郑中拓";
p.eat();
p.sleep();
p.study();//子类Person 独有的方法
}
}
子类Person的对象可以使用,独有的方法
//Person类中重写方法,原代码中加上下面这个新的重写方法
//方法重写
public void eat(){
System.out.println("人类的吃饭方法 讲究色香味俱全");
}
结果在主方法中调用p.eat()的时候,发现重写成功。输出:人类的吃饭方法 讲究色香味俱全。
方法重载和方法重写:
方法重写override | 方法重载overload | |
---|---|---|
类 | 产生两个继承关系的类,子类重写父类的方法 | 一个类中的一组方法 |
权限 | 子类可以大于等于父类 | 没有要求 |
特征final | 父类方法是final 子类不能重写 | 没有要求 |
特征static | 父类方法是static 子类不存在 | 没有要求 |
特征abstract | 父类方法是abstract 子类必须重写 | 没有要求 |
返回值 | 子类可以小于等于父类 | 没有要求 |
名字 | 子类与父类一致 | 一个类中的好多方法名必须一致 |
参数 | 子类与父类一致 | 每一个方法的参数必须不一致(个数 类型 顺序) |
方法体 | 子类的方法内容与父类不一致 | 每一个重载的方法 执行过程不一致 |
异常 | 如果父类方法抛出运行时异常 ,子类可以不予理会。如果父类方法抛出编译时异常,子类抛出异常的个数少于等于父类,子类抛出异常的类型小于等于父类 | 没有要求 |
方法体 | 子类的方法内容与父类不一致 | 执行过程不一致 |
每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类。
可以理解为Object类非常重要,是任何一个引用类型的父类(直接或间接的继承Object) ,Object类没有父类。
Object类中的方法:
hashCode()
将对象在内存中的地址经过计算得到一个int整数
equals()
用来比较两个对象的内容
toString()
打印输出时将对象变成String字符串
getClass()
获取对象对应类的类映射(反射)
wait()
线程进入挂起等待状态 存在方法重载
notify()
线程唤醒
notifyAll()
唤醒所有
finalize()
权限修饰符是protected 在对象被GC回收的时候 默认调用执行的方法
clone()
权限修饰符是protected 为了克隆对象
Java中继承是单个存在的(单继承) 每一个类只能有一个继承类 (在extends关键字后面只能写一个类)。
可以通过传递的方式实现多继承的效果,后续还会有多实现。
继承在内存中的存储形式。剥洋葱。
//基类
public class Animal {
public Animal(){
System.out.println("animal中无参数的构造方法");
}
public void eat(){
System.out.println("动物的吃饭方法");
}
}
//子类:Person
public class Person extends Animal {
public Person(){
//隐藏一行代码 super();调用了父类的构造方法,所以执行了animal中无参数的构造方法
System.out.println("person中的无参数构造方法");
}
//方法重写
public void eat(){
System.out.println("人类的吃饭方法 讲究色香味俱全");
}
}
//主方法
public class Test {
public static void main(String[] args){
Person p = new Person();
}
p.hashcode();
p.eat();
}
发现输出结果是:
animal中无参数的构造方法
person中的无参数构造方法
为什么会有:animal这个的构造函数呢???因为Person的构造函数,隐藏了一行:super();调用了父类的构造方法,所以执行了animal中无参数的构造方法。
主方法中执行过程:
加载类模板的过程,
Person类 Animal类 Object类,
Person p = new Person();
创建一个Person类型的对象,
通过new, 堆内存中申请空间,然后创建了一个变量p,将地址传给了p,p指向了堆内存的那个空间。
假设继续执行p.hashcode()
方法,如何执行的呢?首先通过p找到了堆内存,然后一层一层找,发现第一层没有hashcode()
方法,在进入第二层,父类Animal那一层,发现也没有hashcode()
方法,那就继续下一层Object类中找hashcode()
方法,发现有,那么可以调用。
p.eat()执行,以后一个输出为:人类的吃饭方法 讲究色香味俱全。因为同样类似上面那种查找方式,发现第一层就找到了eat()方法,所以直接调用方法,不用再找第二层第三层了。
public class Animal {
public Animal(){
System.out.println("animal中无参数的构造方法");
}
public void eat(){
System.out.println("动物的吃饭方法");
}
public void sleep(){
this.eat();
//?动物吃饭 人类重写的吃饭
//代替是当前调用方法时的那个对象,不一定是当前类
System.out.println("动物的睡觉方法");
}
}
public class Person extends Animal{
public Person(){
//隐藏一行代码 super();调用了父类的构造方法,所以执行了animal中无参数的构造方法
System.out.println("person中的无参数构造方法");
}
//方法重写
public void eat(){
System.out.println("人类的吃饭方法 讲究色香味俱全");
}
//添加一些独有的属性 或 方法
public void study(){
System.out.println("good good study,day day up");
}
}
//主方法
public class Test {
public static void main(String[] args){
//加载类模板的过程
//Person类 Animal类 Object类
//创建一个Person类型的对象
Person p = new Person();
p.sleep();//从Animal类中继承过来的方法,问题在于Animal中this.eat();到底是调用动物的吃饭方法,还是人类重写的吃饭方法?this指的是当前的对象,当前的对象是人类的对象,所以this指的是人类的吃饭方法。
}
}
//所以结果为:人类的吃饭方法 讲究色香味俱全
p.sleep();
从Animal类中继承过来的方法,问题在于Animal中this.eat();到底是调用动物的吃饭方法,还是人类重写的吃饭方法?this指的是当前的对象,当前的对象是人类的对象,所以this指的是人类的吃饭方法。
那么有一个问题?我就想调用父类的eat的方法呢?这时就用到了super。
this和super都是指代词,代替的是对象。
类的个数变多啦—>需要管理类—>包package(可以理解为是一个文件夹)
在我们类的第一行会出现package关键字
如果package和import同时出现
先写package后写import
包含关系(组合 聚合 关联)
从亲密程度来讲不太一样
从Java程序来描述这样的关系 : 通过一个类的对象当做另一个类的属性来存储
例子:车有轮子
建立Wheel.java
package contains;
public class Wheel {
//属性
public String brand;//品牌
public int size;//尺寸
public String color;//颜色
//构造方法
public Wheel(){}
public Wheel(String brand,int size,String color){
this.brand = brand;
this.size = size;
this.color = color;
}
//方法
public void turn(){
System.out.println("车轮子可以旋转");
}
}
建立Car.java,使用了包含关系:public Wheel wheel;//车里面有一个轮子--->包含关系
想要使用Wheel的属性:wheel.brand
想要使用Wheel的方法:wheel.turn()
package contains;
public class Car {
//属性
public String brand;//汽车品牌
public String type;//型号
public String color;//颜色
public Wheel wheel;//车里面有一个轮子--->包含关系
//构造方法
public Car(){}
public Car(String brand,String type,String color,Wheel wheel){
this.brand=brand;
this.type=type;
this.color=color;
this.wheel=wheel;
}
//方法
public void showCar(){
System.out.println("这是一辆"+brand+"牌"+type+"型号"+color+"的小汽车");
System.out.println("车上搭载着"+wheel.brand+"牌的"+wheel.size+"尺寸"+wheel.color+"颜色的车轮子");
wheel.turn();//方法一定对象调用的
// 车轮子的方法肯定是车轮子对象调用 可以放置在任何地方
}
}
设置一个主函数试验一下:
package contains;
public class Test {
public static void main(String[] args){
Car car = new Car;
car.showCar();//展示汽车
}
}
正常理解,是不应该有错的,但是运行时发现错误。错误指向:
System.out.println("车上搭载着"+wheel.brand+"牌的"+wheel.size+"尺寸"+wheel.color+"颜色的车轮子");
原因在于Wheel是一个空对象,空对象属性是空也不要紧,但是wheel.brand就不行,空对象加点就不可以。所以应当按照下面的样子赋值。
package contains;
public class Test {
public static void main(String[] args){
Car car=new Car();
car.brand="宝马";
car.color="宝石蓝";
car.type="Z4";
car.wheel=new Wheel();
car.wheel.brand="米其林";
car.wheel.color="酷黑";
car.wheel.size=400;
// Car car = new Car("宝马","Z4","宝石蓝色",new Wheel("米其林",400,"酷黑"));
//和上面那一段等价,
//可以用这一句也是因为我们自己定义了构造方法。
car.showCar();//展示汽车
}
}
屠夫 杀 猪 ; 农夫 养 猪
一个类屠夫
可以做一件事情 ,杀猪
需要一头猪
不是整体和部分的关系,某一件事情产生了关系
临时组合在一起,这件事情一旦做完关系即解散
Java程序体现的形式为:
一个类的方法中使用到了另一个类的对象。
设计类的关系遵循的原则:高内聚低耦合
耦合度: 紧密 继承(实现) > 包含 > 依赖
例子:模拟刚刚我们讲过的农民养猪,屠夫杀猪
先写猪的java文件:
package rely;
public class Pig {//描述猪
//属性
private String name;//名字
private int weight = 20;//体重
//构造方法
public Pig(){}
public Pig(String name){
this.name=name;
}
//方法
//描述一个方法 表示小猪被杀啦
public void beKilled(){
System.out.println(this.name+"被杀啦,好惨呀");
}
//描述一个方法 让猪长肉
// 每一个月涨到前一个月的两倍
public void growUp(int month){
for(int i=1;i<=month;i++){
this.weight*=2;
}
}
//描述一个方法 猪告知他的体重
public int getWeight(){
return this.weight;
}
public String getName(){
return this.name;
}
}
屠夫
package rely;
public class Butcher {//描述屠夫
//属性 名字 有刀
//方法
//描述一个屠夫杀猪的方法 需要提供条件 一头猪
public void killPig(Pig pig){
Pig pig=new Pig("小花");
System.out.println("屠夫执行了杀猪方法");
String pigName = pig.getName();
int pigWeight = pig.getWeight();
System.out.println(pigName+"的体重为:"+pigWeight);
pig.beKilled();
}
}
主方法:
package rely;
public class Test {
public static void main(String[] args){
Butcher butcher = new Butcher();
//屠夫做事--->杀猪
butcher.killPig(pig);
}
}
屠夫只负责杀猪,农夫才养猪,所以加一个农夫。
农夫:
package rely;
public class Farmer {//农夫
//农夫养猪--->
// 参数--->几个月 返回值-->是一头猪
public Pig feedPig(int month){
Pig pig = new Pig("小花");//依赖--->在屠夫的方法中使用到了猪的对象
pig.growUp(month);//20 --> 640
return pig;
}
}
所以屠夫变为了:
package rely;
public class Butcher {//描述屠夫
//属性 名字 有刀
//方法
//描述一个屠夫杀猪的方法 需要提供条件 一头猪
public void killPig(Pig pig){
System.out.println("屠夫执行了杀猪方法");
String pigName = pig.getName();
int pigWeight = pig.getWeight();
System.out.println(pigName+"的体重为:"+pigWeight);
pig.beKilled();
}
}
主方法:
package rely;
public class Test {
public static void main(String[] args){
//创建农夫对象
Farmer farmer = new Farmer();
//农夫做一件事情--->养猪
Pig pig = farmer.feedPig(5);
//创建屠夫对象
Butcher butcher = new Butcher();
//屠夫做事--->杀猪
butcher.killPig(pig);
}
}
总结:
类和类的关系
is-a 继承 实现
继承通过extends关键字 (单继承)
实现通过implements关键字 (多实现 接口)
注意方法重写 方法重载区别 注意Object类及方法 注意内存结构
has-a 组合 聚合 关联
一个类的对象放置在另一个类中作为属性
use-a(need-a) 依赖
一个类的方法中使用到了另外一个类的对象
方法内部new 方法传递参数
类关系的设计: 高内聚 低耦合 继承(实现) > 组合 > 聚合 > 关联 > 依赖