面向对象的三大特征
面向对象的三大特征:封装、继承、多态。
一、封装
封装就是把同一类事物的共性(包括属性和方法)归到同一类中,方便使用。 (属性能够描述事物的特征,方法能够描述事物的动作。)
面向对象的封装有两层含义:
1、类,属性、方法这些定义在类
2、为了安全考虑,在开发的过程中,会将属性私有化(private关键字修饰),需要提供对应接口完成设置和访问(公开的setter和getter方法)的过程。
封装:是将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
例如:
电脑的机箱
一台电脑,它是由CPU、主板、显卡、内存、硬盘、电源等部件组成,将 这些部件组装在一起就可以使用电脑了,但是发现这些部件都散落在面,很容造成不安全因素,于是,使用机箱壳子,把这些部件都装在里面,并在机箱壳上留下一些插口等。
封装的好处:
- 提高了代码的复用性。
- 隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用。这是核心之一,也可
以理解为就是封装的概念。 - 提高了安全性。
封装的实现
需要使用一个Java中的关键字也是一个修饰符 private(私有权限修饰符)。
以后再描述事物,属性都私有化,并提供setXxx getXxx方法对其进行访问。
例:
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");//给name赋值
p.setAge(23);//给age赋值
System.out.println(p.getName());//获取name赋的值
System.out.println(p.getAge());//获取给age赋的值
}
}
class Person{
//私有化属性
private String name;
private int age;
//获取name属性
public String getName() {
return name;
}
//设置name属性
public void setName(String name) {
this.name = name;
}
//获取age属性
public int getAge() {
return age;
}
//设置age属性
public void setAge(int age) {
this.age = age;
}
}
单例模式
使用场景:某类创建对象只能且最多只有一个对象。
步骤:
- 私有化构造函数,杜绝外界创建对象。
- 内部创建该类对象(静态)。
- 提供公共接口向外提供该类的对象。
public class Test {
public static void main(String[] args) {
// 懒汉式单例模式
Singleton s1 = Singleton.newInstance();
Singleton s2 = Singleton.newInstance();
System.out.println(s1 == s2);
// 饿汉式单例模式
Singleton2 s3 = Singleton2.newInstance();
Singleton2 s4 = Singleton2.newInstance();
System.out.println(s3 == s4);
}
}
class Singleton {
// 懒汉式
private static Singleton singleton = null;
// 1、私有化构造函数
private Singleton() {}
// 2、创建一个该类的(静态的)对象
public static Singleton newInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
class Singleton2 {
// 饿汉式
private static Singleton2 singleton = new Singleton2();
// 1、私有化构造函数
private Singleton2() {}
// 2、创建一个该类的(静态的)对象
public static Singleton2 newInstance() {
return singleton;
}
}
JOPO对象(Plain Ordinary Java Object)
标准的java bean对象
根据封装来写
私有化属性
提供公开的setter和getter方法
至少两个或者以上的构造方法
例:
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 + "]";
}
}
二、继承
继承
就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
简单来说,继承是把多个类中相同的内容给提取出来定义到一个类中,这个类就叫做父类,又称超类或基类,而多个类就是子类。
注:
Java只支持单继承,不支持多继承。一个类只能有一个父类,不可以有多个父类。
private修饰的属性和方法都是无法被子类继承的。
protected修饰的方法,就是用来给子类继承!!!
继承的好处:
1、继承的出现减少了代码的重复,提高了代码的复用度,提高软件开发效率。
2、继承的出现让类与类之间产生了关系,提供了多态的前提。
继承的格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
Student类和Worker类继承于Person类,那么Person类的name和age属性也能被Student类和Worker类使用。
public class Test02 {
public static void main(String[] args) {
Student s = new Student();
s.name = "小明";
s.age = 23;
s.study();
Worker w = new Worker();
w.name = "张三";
s.age = 45;
w.work();
}
}
class Person {
String name;
int age;
}
class Student extends Person{
public void study(){
System.out.println(name + "同学正在学习。。。。");
}
}
class Worker extends Person {
public void work() {
System.out.println(name + "工人正在工作。。。。");
}
}
方法重写(覆盖)
重写(OverWrite)、覆盖(OverRide)
发生在继承中,当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
访问修饰符 返回值类型 名称一致() {
}
例:
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
cat.eat();
dog.eat();
}
}
class Animal{
private String name;
private int age;
public void eat(){
System.out.println("吃东西");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("小狗啃骨头");
}
}
super关键字
super在java中,是一个指针,类似于this关键字
this关键字指向创建的每一个对象
super会自动指向父类
super(); // 调用父类的无参构造
例:
class Animal{
private String name;
private int age;
public void eat(){
System.out.println("动物需要吃东西");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("小猫吃鱼");
super.eat();//调用父类的eat方法
}
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
}
}
对象的创建流程:
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、执行完成,子类构造函数弹栈,将对象的内存空间地址赋予相应的引用变量
三、多态
多态是面向对象三大特征之一。在继承基础上,才有多态。
概念:父类引用指向子类实例。
List list = new List(); // 创建List对象
List list = new ArrayList(); // 多态
多态的实现的必要条件:
- 存在继承关系
- 存在方法重写
- 父类引用指向子类对象
多态的优点
- 简化了代码
- 提高了维护性和扩展性
多态的弊端
通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
例如:
public class Test {
public static void main(String[] args) {
// 创建一个动物类
Animal animal = new Animal();
animal.say();
// 创建了一个猫类
Cat cat = new Cat();
cat.sayHello();
cat.say();
//如果使用多态创建的猫类
Animal cat2 = new Cat();
cat2.say();
// 多态,父类引用是无法访问到子类自身定义的方法
// 但是父类引用可以直接操作子类重写的方法
}
}
class Animal{
private String name;
private int age;
public void say() {
System.out.println("我是个动物");
}
}
class Cat extends Animal{
public void sayHello() {
System.out.println("cat类的方法");
}
@Override
public void say() {
System.out.println("子类的say方法");
}
}