Java 面向对象
对对象进行抽象
在Java编程时,最重要的能力就是对Java对象进行抽象。完成的抽象过程分别是 抽象对象的名称、抽象对象的属性、抽象对象的方法。比如对于一个户型图来说,户型图会决定房子的构造与布局,整个房子的结构会和户型图上面所描述的保持一致(我们可以通过一个户型图来确定一个房子的信息),所以在Java中对象也和上面的户型图那样。把房子设计成一个户型图就是抽象的过程,在Java的面向对象中,我们把上述的抽象过程视为面向对象编程。
户型图
抽象⬇
房子总结抽象的步骤就是
- 抽象对象的名称(归类)
- 抽象对象的属性(发现类的特征)
- 抽象对象的方法(发现类的行为)
类和对象的概念
类是对象的蓝图,对象是类的实例;类是对象的抽象,对象是类的具体。
类是一系列具有共同属性和行为的事物的抽象,我们可以根据这个蓝图构建出各种各样不同属性的实例,甚至每个实例对象都可以不同。对一个House对象,我们可以设置它的颜色是绿色,也可以是红色,我们可以根据这一个蓝图创建出多个不同的实例对象。
比如我们对房子进行抽象的话
public class House {
/**
* 对象属性
*/
// 房子的颜色
private String color;
// 房子的房间数
private int rooms;
/**
* 对象方法
*/
// 打开空调
public void turnOnAC() {
//code
}
// 打开电扇
public void turnOnFan() {
//code
}
/**
* Getter and Setter
*/
/**
* Override
* toString
*/
}
Java对象(House)会包含 对象属性 和 对象方法
对象属性
我们在对Java对象进行创建的时候,会给它赋予一系列对象都具有的属性,这种就是对象属性,比如有只小狗三岁了,毛色是灰色。我们在狗的类中,我们就可以抽象出年龄属性age和毛色属性color。
public class Dog {
private int age;
private String color;
/**
* Method
*/
/**
* Getter and Setter
*/
/**
* Override
* toString
*/
}
并且我们还可以指定对象的默认属性。假如我们现在有的一批狗,全都是纯种紫色的,我们就可以在设置对象属性的时候赋予它color = “purple”;
对象方法
类或者对象的行为称为方法,我们可以理解为:一个对象在类中可以做很多事情,能做什么在类里面就叫做方法。比如我们定义了一个猫类,猫会吃、喝、打滚和睡觉。我们就可以对其的方法这样定义
public class Cat {
/**
* Attribute
*/
public void eat() {
//code
}
public void drink() {
//code
}
public void roll() {
//code
}
public void sleep() {
//code
}
/**
* Getter and Setter
*/
/**
* Override
* toString
*/
}
构造函数
构造函数对象中一个特殊的方法,它的格式是
public class Cat {
/**
* Attribute
*/
private int age;
private String color;
/**
* Method
*/
// 构造函数不带返回值,名称和类名一模一样
// 空参构造,不写也会自带的构造函数
public Cat() {}
// 对构造函数进行重载
public Cat(int age , String color) {
this.age = age;
this.color = color;
}
/**
* Getter and Setter
*/
/**
* Override
* toString
*/
}
构造函数的作用就是为对象进行初始化工作,初始化类对象的属性,而要实例化一个对象的话我们需要使用到new关键字。
实例化对象
我们在对一个类构造完毕后,我们可以通过new关键字去实例化这个对象。例如:
Cat cat1 = new Cat();
Cat cat2 = new Cat(3 , "purple");
两种对象初始化均可以,因为我们对方法进行了重载,当实例化一个对象的时候,会优先调用与构造函数参数列表接近的那个。
封装
封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。
这样可以防止类中封装的信息被外部类中的代码随意访问。
实现封装的步骤
- 修改属性的可见性来限制对属性的访问
我们在上面对于Cat类创建时,里面用到的age和color就是设置访问权限为private来实现第一步
private int age;
private String color;
- 对每个值属性提供对外的公共方法访问,也就是创建Setter与Getter方法来用于对于上面第一步封装的私有属性进行访问。
private int age;
private String color;
/**
* Getter and Setter
*/
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
继承
什么是继承?
“继承”是面向对象中的第二特征,体现了类与类之间的“is-a”关系。当两个类进行继承关联绑定的时候,子类自动具备来自于的父类的属性和行为,做到代码的复用和设计的分离。
在多个类中存在相同属性和行为的时候,将这些内容抽取到一个单独的类中,那么这些类就无需重复去定义这些相同的属性和行为,只需要去继承我们抽取到的那个类就可以了。抽取出来的这个类称为父类(超类), 而继承这个抽取出来的那些类被称为子类,他们之间使用子类 extends 父类的方式进行继承关联的绑定。
继承的优点
- 提高代码的复用性,减少代码冗余,可以提高程序的运行效率。
- 让类与类之间产生关系,是多态的前提。
就像Dog与Cat同时继承于Animal,它们都有的属性就归到Animal中,由两个类变为了一个类,从而实现提高代码的复用性。
并且在多态中可以使用Animal animal= new Dog();
的方式实例化Dog对象,并在创建的这个对象中只能调用Animal的相关属性和Dog重写的方法。
extends与implements
在Java中可以用extends和implements来完成继承,并且由于Java中extends仅能继承一个类,但implements可以实现多个接口。而且在二者同时出现的时候,必须要先extends才能implements。
多态
多态是继封装以及继承之后的,面向对象的第三大特性。**多态是同一个行为具有多个不同表现形式或形态的能力。**即指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。
前面继承中,提到了类与类之间的"is-a"关系,它表明子类的每个对象也是父类的对象,就像水果(Fruit)和苹果(Apple),我们可以知道Apple也是Fruit,但Fruit不一定是Apple。
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
public class Test {
public static void main(String[] args) {
Fruit fruit;
fruit = new Fruit();
fruit = new Apple(); //没有问题
System.out.println(fruit.name) // fruit
System.out.println(fruit.type) // error
fruit.show(); // I am Apple!
}
}
public class Fruit {
public String name = "fruit";
public void show() {
System.out.println("I am Fruit!")
}
}
public class Apple extends Fruit{
public String type;
public void show() {
System.out.println("I am Apple!")
}
}
此时我们只能调用Fruit中的属性,并且调用的方法是Apple中。这也就是多态成员的特点。
对于多态的成员变量来说:编译和运行都看左边。
对于多态的成员方法来说:编译看左边,运行看右边。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 灵活性
多态的转型
向上转型
子类引用的对象转换为父类类型称为向上转型。就像上面的 Fruit fruit = new Apple();
即是完成了向上转型的过程。
这个时候fruit引用的show
方法也即是Apple的类方法show
向下转型
在 Fruit fruit = new Apple();
的基础上,我们可以使用Apple apple = (Apple) fruit ;
的方式将fruit向下转型为apple,但是也只能转换为apple,即使现在有一个Orange类,也无法将fruit强转为Orange类的实例对象,因为我们已经知道了fruit本身就是Apple对象。此时如果是在 Fruit fruit = new Fruit();
的基础上使用Apple apple = (Apple) fruit ;
的方式,也同样会报错。就像蒙住你的眼睛告诉你眼前是一直动物,你只知道它是动物,但你不知道它到底是猫还是狗。