面向对象三大特性
1. 封装
封装就是将描述一个类的属性和行为的代码封装在一个模块中。
这样做的好处:
提高了代码的复用性
增加了代码的安全性
高内聚 低耦合
对象封装之后,外界只有通过对象的共有方法去得到对象的数据。
我们通过示例进行分析:
未封装时:
public class EncapsDemo {
String name;
int age;
public void getInfo() {
System.out.println("name: " + name + ", age: " + age);
}
}
测试代码如下:
public class EncapsDemoTest {
public static void main(String[] args) {
EncapsDemo encapsDemo = new EncapsDemo();
encapsDemo.name = "李四";
encapsDemo.age = 1000;
encapsDemo.getInfo();
}
}
输出结果:
name: 李四, age: 1000
我们可以看到,没有使用封装,任何人都可以进行复制,信息不安全
当我们使用封装:
public class EncapsDemo1 {
private String name;
private int age;
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 >= 0 && age <= 130) {
this.age = age;
} else {
System.out.println("age输入异常!!!,age范围为0到130");
}
}
public void getInfo() {
System.out.println("name: " + this.getName() + ", age: " + this.getAge());
}
}
测试代码:
public class EncapsDemo1Test {
public static void main(String[] args) {
EncapsDemo1 encapsDemo1 = new EncapsDemo1();
encapsDemo1.setName("李四");
encapsDemo1.setAge(1000);
encapsDemo1.getInfo();
}
}
输出结果:
age输入异常!!!,age范围为0到130
name: 李四, age: 0
可以看出:
- private 修饰的成员在自己所在的类可以使用,在类外不可以,只可以通过set/get去调用属性
- 在set方法内可以加入逻辑判断,过滤掉非法的数据
2. 继承(重写)
子类继承父类,使用“ extends ”
格式:
class 子类 extends 父类{}
当子类继承父类时,会自动拥有父类可以被继承的成员
继承的好处:
- 提高了代码的复用性
- 提供了多态的前提
示例如下:
创建一个父类,一个子类
package com.oracle.demo03;
//员工类(父类)
public class employee {
String name;
public void speak(){
System.out.println("员工正在工作");
}
}
package com.oracle.demo03;
//研发类员工(子类)
//子类继承父类:自动拥有所有可继承的成员
public class developer extends employee {
}
再创建一个测试类
package com.oracle.demo03;
public class test {
public static void main(String[] args) {
developer d= new developer();
d.name = "zhangsan";
d.speak();
System.out.println(d.name);
}
}
输出结果如下:
3. 多态
-
首先我们要知道,什么是多态?
多态就是在面向对象语言里,接口的多种不同的实现方式。
在java开发里,多态的实现主要通过方法重载和方法重写来实现。 -
代码讲解
定义一个父类 Anmial 一个Cat类,Cat类继承Animal类
package com.demo;
//Animal类
public class Animal {
void eat(){
System.out.println("动物吃饭");
}
void sleep(){
System.out.println("动物睡觉");
}
}
package com.demo;
//继承于Animal类的Cat类
public class Cat extends Animal {
//重写父类 Animal类里的 sleep方法
void sleep(){
System.out.println("猫躺着睡觉");
}
//重写eat方法
void eat(){
System.out.println("猫吃鱼");
}
//在子类里增加一个方法
public void run(){
System.out.println("猫抱着很舒服");
}
}
创建一个Test测试类:
package com.demo;
public class Test {
public static void main(String[] args) {
//向上转型
Animal animal = new Cat();
animal.eat();
animal.sleep();
//我们进行向下转型
Cat cat = (Cat) animal;
cat.run();
}
}
Animal animal = new Cat(); 使用了向上转型,子类Cat对Animal进行了重写,我们这里使用了父类型Animal去引用子类对象Cat,会先访问到子类重写了父类的部分。
如果子类没有重写父类的方法,才会去执行父类的重写方法
比如,当Animal父类的demo方法没有被Cat子类重写,那么我们通过Animal animal = new Cat(); 执行的是父类Animal里的demo方法。
代码如下:
/Animal类
public class Animal {
void eat(){
System.out.println("动物吃饭");
}
void sleep(){
System.out.println("动物睡觉");
}
void demo(){
System.out.println("动物奔跑");
}
}
Cat类并没有重写demo方法
Test类进行掉用:
package com.demo;
public class Test {
public static void main(String[] args) {
//向上转型
Animal animal = new Cat();
animal.demo();
}
}
调用结果:
- 继续分析,当我们要调用子类的方法时,需要进行向下转型
那向下转型正确的思路是什么?
就是将已经转为父类型的子类对象,再一次转回为子类型
在上面的例子里,我们使用Animal animal = new Cat(); 进行了向上转型,将Cat子类对象转为父类型,执行的是Cat类覆盖之后的方法。
但我们调用子类自己的方法时,需要转换类型,也就是将父类型的子类对象转为原来的子类型
使用 Cat cat = (Cat) animal; 进行向下转型
- 多态的优劣;
多态提高了代码的可扩展性,符合开闭原则。
但多态也无法调用子类自己的方法