第5篇 Java面向对象
Java面向对象
类
具有相同属性和方法的一系列对象的集合,是对对象的一个描述。类的内部包括属性和方法两个部分。
类是创建对象的一个模板。
命名规范:帕斯卡命名法
类的声明:
class Dog{ //属性 private String name; private int age; private float height; //构造方法 public Dog() { } public Dog(String name, int age, float height) { super(); this.name = name; this.age = age; this.height = height; } //方法 public void eat() { System.out.println("这只狗会吃饭..."); } //Getter & Setter public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } }
属性
一般情况下,所有属性设置为private(只能在本类进行访问)
属性是对对象特征的一个描述。在描述对象时,不需要对对象的所有特征都进行描述,只需用到什么就描述什么。
方法
方法包括五部分:限定词+返回值类型+方法名+参数+方法体
方法在定义时的参数为形参,只起到占位作用。形参是一个局部变量,作用域仅仅限于方法体内有效,出了方法体,便被销毁。
方法在被调用的时候传入的参数称为实参,它的值被赋给形参,通过形参参与方法体中的运算。这种值的传递是单向的,只有从实参传递给形参,方法执行完毕之后,形参的值并不会被传递给实参。
方法重载
- 方法名相同
- 方法参数列表不同
- 与返回值和限定修饰符无关
- 发生在同一个类当中
public class Calc{ //被重载的方法 public int add(int num1, int num2) { return num1+num2; } //参数列表不同,方法名相同 public int add(int num1, int num2, int num3) { return add(num1, num2)+num3; } //参数名与返回值都不同,方法名相同 public float add(float num1, float num2) { return num1+num2; } }
构造方法
每个类都有自己的构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的无参构造方法。
构造方法的几个特点:
- 方法名与类名相同
- 没有返回值
- 建立对象时自动被调用
- 一个类至少有一个到多个构造方法
对象
对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。
对象是类所描述的一个实体,是类的一个实例化。
创建对象
- 声明:声明一个对象,包括对象名、对象类型、
- 实例化:使用关键字new来创建一个对象
- 初始化:使用new创建对象时,会调用构造函数来对对象进行初始化
示例:
//调用无参构造方法实例化对象 Dog dog1 = new Dog(); //调用带参构造方法实例化对象,同时对对象进行初始化 Dog dog2 = new Dog("大黄", 2, 12.9f);
访问对象
由于对象的属性被设置为私有的,所以只能通过set和get方法来访问。
通过已创建的对象来访问成员变量和成员方法,如下所示:
Dog dog2 = new Dog("大黄", 2, 12.9f); System.out.println("狗的名字是:"+dog2.getName()); System.out.println("狗的年龄是:"+dog2.getAge()+"岁"); System.out.println("狗的体重是:"+dog2.getHeight()+"kg");
打印结果如下:
狗的名字是:大黄 狗的年龄是:2岁 狗的体重是:12.9kg
面向对象
基本特征
-
封装
-
继承
-
多态
面向对象的特点
- 一种常见的思想,符合人们的思考习惯
- 将复杂问题简单化
- 从执行者变为指挥者
设计过程
- 发现类
- 发现类的属性
- 发现类的方法
- 优化过程
设计的原则:关注所需要的属性和方法
Java 封装
优点:
- 良好的封装可以减少耦合
- 类内部结构可以自由修改
- 可以对成员变量进行更精确的控制
- 隐藏信息,实现细节
访问权限
一般情况下,将属性值全部设置为private,通过set和get方法来对属性进行访问:
public class Person{ private String name; private int age; public int getAge(){ return age; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public void setName(String name){ this.name = name; } }
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法实现对隐藏信息的访问和操作。
Java 继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。同时,子类可以在父类的基础上进行扩展,加入自己独有的属性和方法。
- Java中通过extends关键字来表明一个类与其父类的继承关系
- 子类将会继承父类除私有以外所有的属性和方法(个人认为私有的仍然被继承,但是由于作用域的原因无法被使用)
- 子类可以在父类的基础上进行扩展
- 继承关系中方法的执行顺序:先从子类中查找该方法,如果在子类中找不到该方法则再去父类中查找
- Java中属于单继承,一个子类只能拥有一个父类,一个父类可以拥有N个子类
- 构造方法不能也无需被继承,因为在调用子类的构造方法时会默认先调用父类的构造方法
- 继承的初始化顺序:父类构造方法 --> 父类属性初始化 --> 子类构造方法 -->子类属性初始化
- Java中super关键字代表父类,子类中可以使用super来调用父类的共有属性和方法
- Java中this关键字代表当前类,通过this关键字可访问本类中所有属性和方法
class Animals{ private String name; //父类构造方法 public Animals(String name) { this.name = name; } public void eat() { System.out.println("动物吃东西"); } } class Dogs extends Animals{ //子类构造方法。父类没有无参构造方法,子类实例化时必须调用父类构造方法 public Dogs(String name) { super(name); } public void run() { System.out.println("狗会跑"); } }
上面例子中,Animals为父类,而Dogs作为子类。
Animals中只有一个Animals(String name)的构造方法。子类构造方法中,如果没有使用super来调用父类构造方法,编译器会默认调用一个super()的方法,但由于父类中不存在这个构造方法,所以编译器会报错。此时要求我们调用父类唯一的带参构造方法。
子类构造方法中必须且只能一次地调用父类的构造方法,并且位置是在构造方法所有操作之前。
run方法是Dogs类在Animals类的基础上所进行的扩展,eat方法将在Dogs类中被继承。
继承后对Dogs对象的使用示例:
Dogs dogs = new Dogs("大黄"); dogs.eat(); dogs.run();
打印结果如下:
动物吃东西
狗会跑
方法的重写
子类中可以对从父类继承的方法进行重写(Alt+Shift+s, v),重写后子类对象在调用时会优先调用子类中被重写的方法
class Dogs extends Animals{ public Dogs(String name) { super(name); } //对父类方法进行重写,通过@verride标识 @Override public void eat() { System.out.println("狗会吃骨头"); } }
这里调用dogs.eat()方法时,会打印“狗会吃骨头”,而不是“动物吃东西”。
super、this关键字
super代表的是父类,this代表的是本类
class Dogs extends Animals{ public Dogs(String name) { super(name); } @Override public void eat() { System.out.println("狗会吃骨头"); } public void animalEat() { super.eat(); this.eat(); } }
调用animalEat方法后打印的结果为:
动物吃东西
狗会吃骨头
final关键字
final,意为最后的,最终的。
- 被final修饰的类不能被继承
- 被final修饰的方法不能被重写
- 被final修饰的属性被能被修改(常量)
继承与组合的区别
B extends A : 从逻辑上来说,是 “B is a A” 的关系。例如狗继承自动物,说明狗是一种动物;衣服继承自商品,说明衣服是一种商品。
组合:是一种 “A has B” 的关系。在一个类中,可以用别的对象来作为自己的属性。例如人有名字,而这个名字本身是一个String类型的对象,我们可以同过它来描述一个人。
Java 多态
- 多态即父类的引用执行子类对象
- 多态必须建立在继承的基础上(对接口的实现上)
- 多态中方法调用时现在子类查找该方法,没有找到则再去父类中查找
所为多态,即多种形态。
多态是同一个行为具有多个不同表现形式或形态的能力。
比如说两台打印机,一台为黑白打印机,一台为彩色打印机。当我们使用黑白打印机时,它将给我们打印黑白的材料,而使用彩色打印机时打印的却是彩色的。
abstract class Printer { //父类的打印方法 public abstract void print(); } class BWPrinter extends Printer { @Override public void print() { System.out.println("打印了一份黑白材料"); } } class ColorfulPrinter extends Printer { @Override public void print() { System.out.println("打印了一份彩色材料"); } } public class Main { public static void print(Printer printer) { printer.print(); } public static void main(String[] args) { BWPrinter bwPrinter = new BWPrinter(); ColorfulPrinter colorfulPrinter = new ColorfulPrinter(); //使用黑白打印机进行打印 print(bwPrinter); //使用彩色打印机进行打印 print(colorfulPrinter); } }
打印结果为:
打印了一份黑白材料
打印了一份彩色材料
多态的优点
- 消除类型之间的耦合
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象