面向对象的三大特性
封装
什么是封装:
在类中,对于不想被类外直接访问的成员变量,进行一个私有化,同时提供一个公共的方法访问私有的成员,尽可能的隐藏内部的细节,控制修改以及访问对象的权限。
封装的步骤:
-
添加private修饰符(private私有的,只能本类内进行访问,这样就限制了外部其他类访问的权限)
-
添加get和set方法(对外暴露的公共方法,每次外部类想要修改或者访问属性的时候,必须通过公共的方法)
语法:
//get方法 public 属性类型 getXXX(){ return 属性; } //set方法 public 属性类型 setXXX(参数类型 参数){ this.xxx=参数; }
示例:
public class Person { private String name; private int age; private String sex; public String getName() { return name; } public void setName(String name) { this.name=name; } public int getAge() { return age; } public void setAge(int age) { if(age>100||age<1) { this.age=18; }else { this.age=age; } } public String getSex() { return sex; } public void setSex(String sex) { if(sex.equals("男")||sex.equals("女")) { this.sex=sex; }else { this.sex="男"; } } public void eat() { System.out.println(name+"开始吃饭..."); } public void study() { System.out.println(name+"开始努力学习..."); } public void show() { System.out.println("姓名:"+name+" 年龄:"+age+" 性 别:"+sex); } }
继承
概念:
在原有类的基础上,产生一个新的类,在新的类中可以访问原有类中的非私有成员,并且可以添加自己独有的成员,这个过程叫做继承,简单理解为一个类继承了另外的一个类。
好处:
实现代码的重复利用;模拟了现实世界的关系。
类的继承的使用:
使用extends关键字实现2个类的继承关系;被继承的类叫做父类,超类,基类,继承的类叫做子类,派生类;继承之间需要满足 is a 的关系。
语法:
public class FatherClass{
//属性 //方法
}
public class ChildClass extends FatherClass {
//属性 //方法
}
子类对象实例化的过程:
先实例化父类对象,默认调用父类的构造方法,然后在实例化子类对象
不能被子类继承的成员:
- 私有成员
- 构造方法:父类的构造方法不能被子类所继承,但是会在子类的构造方法中调用(子类的构造方法,默认第一句是调用父类的构造方法:super())
继承的特点:
- 单继承:一个子类只能有一个父类,一个父类可以有多个子类,所有继承的资源非常的珍贵
- 传递性:继承具有传递性,即爷爷的公共方法或者属性,孙子也有。
注意:
this 当前对象 :
1.区别局部变量和实例变量 this.属性 this.方法
2.this() 调用本类里的其他构造方法
super 父类:
1.super 调用父类的属性和方法
2.super() 调用父类的构造方法
所有构成继承的关系的类,所有子类的构造函数都默认提供
super(),即先调用父类的构造方法再调用子类的构造方法
super和this不能再同一个构造函数中出现
多态
什么是多态:
在生活中,一类事物有多种的表现形态,对象的多种形态,比如:某个音乐家有三个儿子,大儿子会唱美声,二儿子会唱流行,三儿子唱摇滚。
程序中,多态:同一个父类引用类型,使用不同的子类实例而执行不同操作 ,一句话理解:父类变量,子类对象。或者叫做:父类引用指向子类对象。
父类引用仅可调用父类所声明的属性和方法,不以调用子类独有的方法和属性如果子类覆盖了父类的方法,父类引用调用方法时会优先执行子类覆盖的方法。
案例:
要求:
-
编写一个宠物类 Pet 属性:id,name,health,love ;方法有print(),打印信息,要封装成员变量。
-
两个子类狗狗和猫类,狗狗有品种(strain),猫类有爱好(hobby),重写父类print()方法
-
3.宠物饿了,需要主人给宠物喂食,狗狗吃狗粮、猫咪吃小鱼,吃完之后健康值狗狗增加3,猫咪增加5。
代码演示:
/*宠物类 */
package com.qf.day08;
public class Pet{
private int id;
//id 宠物编号
private String name;
// 宠物昵称
private int health;
// 健康值
private int love;
// 亲密度
public void setId(int id){
this.id=id;
}
public int getId(){
return id;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setHealth(int health){
this.health=health;
}
public int getHealth(){
return health;
}
public void setLove(int love){
this.love=love;
}
public int getLove(){
return love;
}
//方法
public void print(){
System.out.println("宠物id:"+this.id+",宠物昵称:"+this.name+",健康值:"+health+", 亲密度:"+love);
}
}
/*dog类继承Pet类 */
package com.qf.day08;
public class Dog extends Pet{
private String strain;
public void setStrain(String strain){
this.strain=strain;
}
public String getStrain(){
return strain;
}
public void print(){
int id=getId();
String name=getName();
int health=getHealth();
int love=getLove();
System.out.println("狗狗id:"+id+" 昵称:"+name+" 健康值:"+health+" 亲密度:"+love+" 品种:"+strain);
}
public void eat(){
String name=getName();
System.out.println(name+"大口吃狗粮....");
//增加健康值
int health=getHealth();
setHealth(health+3);
}
}
/*猫类*/
package com.qf.day08;
public class Cat extends Pet{
private String hobby;
public void setHobby(String hobby){
this.hobby=hobby;
}
public String getHobby(){
return hobby;
}
public void print(){
int id=getId();
String name=getName();
int health=getHealth();
int love=getLove();
System.out.println("猫咪id:"+id+" 昵称:"+name+" 健康值:"+health+" 亲密度:"+love+" 爱好:"+hobby);
}
public void eat(){
String name=getName();
System.out.println(name+"大口吃小鱼....");
//增加健康值
int health=getHealth();
setHealth(health+5);
}
}
/*主人*/
package com.qf.day08;
public class Master{
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
//喂食
public void feed(Dog d){
System.out.println(name+"要给狗狗喂食物...");
d.eat();
d.print();
}
public void feed(Cat c){
System.out.println(name+"要给猫咪喂食物...");
c.eat();
c.print();
}
}
package com.qf.day08;
public class TestPet{
public static void main(String[] args){
Dog afu=new Dog();
afu.setId(120);
afu.setName("阿福");
afu.setHealth(85);
afu.setLove(90);
afu.setStrain("拉布拉多");
afu.print();
Cat amao=new Cat();
amao.setId(119);
amao.setName("阿猫");
amao.setHealth(90);
amao.setLove(70);
amao.setHobby("爬树");
amao.print();
Master yuhuan=new Master();
yuhuan.setName("玉环");
yuhuan.feed(afu);
yuhuan.feed(amao);
}
}
思考:如果添加一个宠物需要给它喂食怎么办,就需要再写一个feed方法,这样就会显得代码的扩展性很差。
多态的使用:
- 编写父类,子类,子类重写父类的方法
- 运行时,使用父类的变量,子类的对象
//喂食
//舍弃feed方法,进行重新的编写,
public void feed(Dog d){
System.out.println(name+"要给狗狗喂食物...");
d.eat();
d.print();
}
public void feed(Cat c){
System.out.println(name+"要给猫咪喂食物...");
c.eat();
c.print();
}
//因为参数的类型为dog或者为cat,但是因为都继承了pet,所以使用pet当做参数
public void feed(Pet p){
String n=p.getName();
System.out.println(name+"要给"+n+"喂食物...");
p.eat();//调用子类重写的方法
p.print();//调用子类重写的方法
}
多态的使用形式:
- 使用父类作为方法的形式参数
- 使用父类作为方法的返回值实现多态
- 重载,重写都是多态的表现形式
转型
因为存在了父类引用产生子类的,所以就有了转型
向上转型(装箱):将子类的对象赋值给父类变量,自动转换
Pet pet1 = new Dog();
Pet pet2 = new Cat();
String str = "abc";
Object obj = str;
注意:
1 <父类型> <引用变量名> = new <子类型>();
2 此时通过父类引用变量调用的方法是子类重写或父类的方法,编译时看父类,运行时看子类
3 此时通过父类引用变量无法调用子类特有的属性和方法
向下转型(拆箱):将父类的变量赋值给子类变量,强制转换
Object obj = new String("abc");
String str = (String)obj;
Pet pet=new Dog(); // Pet pet=new Cat();
Dog d=(Dog)pet; //向下转型
注意:
1 <子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;
2 在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常ClassCastException
instanceof关键字
对象向下转型的时候,存在一个问题,若一个父类A的引用a,指向一个子类B的实例,将a赋值给另一个子类C引用时,会抛出java.lang.ClassCastException异常;抛出异常后程序将不能继续向下执行,为了避免这个异常的抛出,我们可以通过instanceof关键字判断引用指向的实例是否可以进行强制转换成某个子类对象。
已知Pet类有两个子类Dog和Cat:
public class Demo{
public static void main(String[]args){
Pet a = new Dog();
check(a);
}
//设计一个方法,判断一个动物是猫还是狗
public static void check(Pet a){
if(a instanceof Dog){ //返回值类型是true/false
System.out.println("狗");
}else if(a instanceof Cat){
System.out.println("猫");
}
}
}