面向对象的三大特征:
封装
继承
多态
1. 面向对象的封装有两层含义:
|-- 类,属性、方法等这些封装在类中
|-- 为了安全考虑,在开发的过程中,会将属性私有化(private关键字修饰)。
访问和设置属性:需要提供对应接口完成设置和访问(公开的setter和getter方法)的过程。
package com.openlab.day12;
public class Test01 {
public static void main(String[] args) {
Cat cat = new Cat();
// 设置猫的id
cat.setId(2);
System.out.println(cat.getId());
}
}
class Cat {
// 首先私有化属性
private int id;
private String name;
private int age;
// 获取id的方法
public int getId() {
return this.id;
}
// 设置id的方法
public void setId(int id) {
this.id = id;
}
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;
}
}
2. JOPO对象(Plain Ordinary Java Object)
标准的java bean对象
根据封装来写
私有化属性
提供公开的setter和getter方法
至少两个或者以上的构造方法
package com.openlab.day12;
public class Book {
private int id;
private String name;
private double price;
private Author author;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
public Book() {
}
public Book(int id, String name, double price, Author author) {
super();
this.id = id;
this.name = name;
this.price = price;
this.author = author;
}
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + ", author=" + author + "]";
}
}
package com.openlab.day12;
/**
* 标准的JOPO对象
*
*
*/
public class Author {
private int id;
private String name;
private String gender;
private int age;
private String intro;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getIntro() {
return intro;
}
public void setIntro(String intro) {
this.intro = intro;
}
public Author() {
}
public Author(int id, String name, String gender, int age, String intro) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
this.intro = intro;
}
public Author(String name, String intro) {
super();
this.name = name;
this.intro = intro;
}
@Override
public String toString() {
return "Author [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", intro=" + intro + "]";
}
}
3. 私有化构造函数:
|-- 工具类(静态方法或者静态属性)如Math,Arrays。通过类名访问,不需要创建对象。
|-- 单例模式(一个类只需要一个对象)如任务管理器
饿汉式单例模式:提前准备好了
package com.openlab.day12;
/*public class Singleton {
// 1、私有化构造函数
private Singleton() {}
// 2、给使用者提供一个创建好的对象
public static Singleton newInstance() {
return new singleton();
}
}*/
//这样写每一次创建一个新对象,还不如将构造函数开放,让自己创建
//单例模式只想有一个对象,则不能每一次调用都创建一个
public class Singleton {
// 饿汉式单例模式
private static Singleton singleton = new Singleton();
// 1、私有化构造函数
private Singleton() {}
// 2、给使用者提供一个创建好的对象
public static Singleton newInstance() {
return singleton;
}
}
缺陷:要是一直不用,则白白浪费内存空间(static不管用不用都提前加载内存,直到程序结束,才回收)。由此引出懒汉式单例模式
package com.openlab.day12;
public class Singleton2 {
// 懒汉式单例模式
private static Singleton2 singleton = null;
// 1、私有化构造函数
private Singleton2() {}
// 2、给使用者提供一个创建好的对象
public static Singleton2 newInstance() {
if (singleton == null) {
singleton = new Singleton2();
}
return singleton;
}
}
好处:只有访问了,需要时才会创建(访问之后就和饿汉式一样了)
缺陷:代码
if (singleton == null) {
singleton = new Singleton2();}
//有问题,多线程中,多个人同时访问第一行。假如第一个线程进了,还没来得及创建,第二个线程进来了,此时就会创建两个对象,出问题。(等学完多线程后,会用dcl来解决)
4. 面向对象的专业术语:
OO(Oriented Object):面向对象
OOP(Oriented Object Programming):面向对象的编程
OOD(Oriented Object Design):面对对象的设计
OOA(Oriented Object Analysis):面向对象的分析
OOT(Oriented Object Test):面向对象的测试
在面向对象中,类与类之间可以存在继承关系
在Java中,也存在继承,java是一种典型的单继承编程语言。
1. java如何实现继承:
extends
父类(超类、基类):
子类:
注意:private修饰的属性和方法都是无法被子类继承的
protected修饰的方法,就是用来给子类继承!!!
package com.openlab.day12.inherit;
public class RichMan {
public double money = 100000000;
protected String company = "google";
String car = "兰博基尼";
private String secretary = "秘书";
protected void say() {
System.out.println("好好加油");
}
}
package com.openlab.day12;
import com.openlab.day12.inherit.RichMan;
public class Son extends RichMan {
public static void main(String[] args) {
// 开始执行创建对象的代码
Son son = new Son();
System.out.println(son.car);//不报错
System.out.println(son.company);//不报错
System.out.println(son.money);//不报错
// System.out.println(son.secretary);报错,私有属性
}
}
2. 继承的功能:
减少代码的重复,提高代码的复用度。(很多类需要同一个方法,将这个方法定义在一个公共的父类中,让其他类继承,从而调用方法)
3. 方法重写(覆盖)
重写(OverWrite)
覆盖(OverRide)
发生在继承中,指的是,子类继承了父类方法后,该方法不能满足子类,
重写该方法,已达到满足子类使用。
访问修饰符 返回值类型 名称一致() {
}
注意:访问修饰符的权限可以扩大,但是不能缩小
//父类为protected,子类可以为protected或者public,不能缩小权限
protected void say() {
System.out.println("请多多关照");
}
4. 注解(annotation):
JDK5.0提供的新特性,利用反射技术,可以很轻松使用标注方法、属性、类等,
从而扩展功能。
@Override // 覆盖
@Deprecated // 过时警告
@SuppressWarnings //压制警告
@Override // 该方法就是重写的方法
protected void say() {
System.out.println("请多多关照");
}
5. super关键字
super在java中,是一个指针,类似于this关键字
this关键字指向创建的每一个对象
super会自动指向父类
super(); // 调用父类的无参构造
//子类新增的方法
public void sayHello(){
super.say();
}
public static void main(String[] args) {
Son son = new Son();
son.sayHello;//会输出父类的say方法
}
6. 对象的创建流程:(考虑继承的情况下)
1、使用java命令将源码(.java)进行编译,生成字节码文件(.class)
2、javac命令执行字节码文件
3、将字节码文件加载进虚拟机(JVM),静态方法区开始加载静态资源
4、JVM从静态方法区读取主函数,并加载进栈(执行栈被创建了出来)
5、main函数开始执行, 创建对象的代码,如:Son son = new Son();
6、在堆内存中开辟对象的内存空间,并分配地址
7、创建成员变量并进行默认初始化
8、子类构造函数从非静态方法区加载进栈开始执行
9、第一句先执行父类的构造函数
10、父类构造函数执行,为子类继承到的成员变量进行初始化(对象内存空间里的父类空间)
11、父类构造函数弹栈执行完成
12、子类构造函数继续执行,此时先对成员变量进行显式初始化
13、再执行子类构造函数的内容,进行针对性初始化
14、执行完成,子类构造函数弹栈,将对象的内存空间地址赋予相应的引用变量
方法区:(Method Area)
元数据区:(Metaspace)
在继承基础上,才有多态
概念:父类引用指向子类实例
List list = new List(); // 创建List对象
List list = new ArrayList(); // 多态
package com.openlab.day13.test;
public class Animal {
public void say() {
System.out.println("我是个动物");
}
}
package com.openlab.day13.test;
public class Cat extends Animal {
public void sayHello() {
System.out.println("cat类的方法");
}
}
package com.openlab.day13.test;
public class Test {
public static void main(String[] args) {
// 创建一个动物类
//Animal animal = new Animal();
//animal.say();父类肯定调的是say()方法
// 创建了一个猫类
//Cat cat = new Cat();
//cat.sayHello();子类能调到的是sayHello()方法
//cat.say();子类也能调到say()方法(继承)
// 如果使用多态创建的猫类
Animal cat2 = new Cat();
cat2.say();//调用的是父类的方法,访问不到子类自己的方法。输出 我是个动物
}
}
多态,父类引用是无法访问到子类自身定义的方法
但是父类引用可以直接操作子类重写的方法
子类重写父类的方法:
package com.openlab.day13.test;
public class Cat extends Animal {
public void sayHello() {
System.out.println("cat类的方法");
}
@Override
public void say() {
System.out.println("子类的say方法");
}
}
此时
Animal cat2 = new Cat();
cat2.say();//调用的是父类的方法,访问不到子类自己的方法。输出 我是个动物
即 父类引用可以直接操作子类重写的方法
用更高层(父类)代替所有的子类,且能调用到子类方法
案例:
package com.openlab.day13.test02;
public class Master {
// 使用多态,代指所有的宠物类型
public void cure(Animal pig) {
if (pig.getHealth() < 60) {
pig.cure();
}
}
public static void main(String[] args) {
QQ qq = new QQ();
qq.setHealth(30); // qq生病了
Master master = new Master();
master.cure(qq);
// Dog 生病了
Dog dog = new Dog();
dog.setHealth(10);
master.cure(dog);
}
}
package com.openlab.day13.test02;
public class Animal {
// 100
private int health;
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
// 动物自身存在一个治疗自己的方法
// 该方法,存在的意义就是用来重写,因此函数体的代码就没有意义
public void cure(Animal pig){
}
}
package com.openlab.day13.test02;
public class QQ extends Animal {
@Override
public void cure() {
if (this.getHealth() < 60) {
System.out.println("给冰块");
System.out.println("给水,让它玩");
this.setHealth(100);
} else {
System.out.println("琪琪需要和你玩");
}
}
}
package com.openlab.day13.test02;
public class Dog extends Animal {
@Override
public void cure() {
if (this.getHealth() < 60) {
System.out.println("狗狗生病了");
System.out.println("打针,吃药");
this.setHealth(100);
} else {
System.out.println("狗狗很健康");
}
}
}
package com.openlab.day13.test02;
public class Cat extends Animal {
@Override
public void cure() {
if (this.getHealth() < 60) {
System.out.println("打吊针");
System.out.println("吃罐头");
this.setHealth(100);
} else {
System.out.println("喵喵需要和你玩");
}
}
}