面向对象的三大特征:封装,继承,多态
封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。就好像我们看不到挂在墙上的空调的内部的零件信息(也就是属性),但是可以通过遥控器(方法)来控制空调。如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。就好像如果没有空调遥控器,那么我们就无法操控空凋制冷,空调本身就没有意义了。
实例:
public class Main{
public static void main (String[] args){
Student student1 = new Student();
student1.setid(3);
student1.setname("小花");
//student1.name = "xiaoming"; 不对,java和python不一样,不能这么赋值
System.out.println(student1.getid()); //3
System.out.println(student1.getname()); //小花
//System.out.println(student1.id); //The field Student.id is not visible 提示变量不可见,因此不能显示
}
}
class Student{
private int id;
private String name;
//定义一个获取id的方法
public int getid(){
return id;
}
//定义一个设置id的方法
public void setid(int id){
this.id = id;
}
//定义一个获取name的方法
public String getname(){
return name;
}
//定义一个设置name的方法
public void setname(String name){
this.name = name;
}
}
继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。
关于继承如下 3 点请记住:
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
- 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
一个例子:
public class Main {
public static void main(String[] args) {
Goo o = new Goo();
o.f(); //输出结果为 Goo.f()
Foo oo = new Goo(); //由父类调用子类
oo.f(); //输出结果也为 Goo.f()
}
}
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
class Goo extends Foo{ //继承父类Foo去定义子类Goo
public void f(){
System.out.println("Goo.f()");
}
}
关于继承的重写具体实例可以参考1022_学习重写和继承中遇到的那些坑
多态
表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例。
多态的特点:
- 对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
- 引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
- 多态不能调用“只在子类存在但在父类不存在”的方法;
- 如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。
一个例子
实现这样一个功能:定义一个大类Animal,里面有两个子类Cat和Dog,猫和狗都有两种行为(方法):eat和work,但是有自己的不同:
public class Main {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
//show在这里定义
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { //instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
// 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal { //抽象类
abstract void eat();
abstract void work();
}
/*
并不是所有的类都是用来描绘对象的,
如果一个类中没有包含足够的信息来描绘一个具体的对象,
这样的类就是抽象类。
*/
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
从主函数开始分析:
show(new Cat());
// 以 Cat 对象调用 show 方法
去定义show:
\qquad 1.1 show的输入为Animal a,show去判断是Cat类还是Dog类,使用了if语句if (a instanceof Cat)
\qquad 1.2 如果判定是猫,Cat c = (Cat)a; c.work();
其实这个里面为了简化把a.eat()
拎出去了 ,实际上也可以定义在里面,这样维护成本更低一点,代码也更整齐可读。之前看《head first java》那本书其实有更好更详细的例子,有时间再贴过来。- 实例化类
Animal a = new Cat()
一个新的猫类实例为a
去定义Animal :
\qquad 2.1abstract class Animal
定义一个抽象类,里面有各种抽象方法
\qquad 2.2abstract void eat();
定义各种抽象方法 - 去定义Animal 的子类Cat:
\qquad 3.1class Cat extends Animal
继承父类Animal的子类Cat
\qquad 3.2public void eat()
公开可变的,public,去定义具体方法(在父类Animal里面是一个抽象方法,这里具体化) - Dog同理
运行结果:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。