28.面向对象编程
- 面向过程思想
- 步骤简单清晰,第一步做什么,第二步做什么…
- 面向过程适合处理一些较为简单的问题
- 面向对象的思想
- 物以类聚,分类思维模式,思考问题首先解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向过程适合处理复杂的问题,适合处理需要多人协作的问题!
什么是面向对象
- 面向对象编程(Object-Oriented Programming.)
- 面向对象编程的本质就是:以类的方式组织代码,以对象组织(封装)数据
- 抽象
- 三大特性
- 封装
- 继承
- 多态
- 从认识论的角度考虑是现有对象后有类。对象,是具体的事物,类,是抽象的,是对对象的抽象
- 从代码的角度考虑是先有类后有对象。类是对象的模板。
方法定义及基础知识回顾
package com.oop.demo;
// Demo01 类
public class Demo01 {
// main 方法
public static void main(String[] args) {
}
/*
* 修饰符 返回值类型 方法名(参数..){
* //方法体
* }
*
* */
public String sayHello() {
return "hello world";
}
/*
* break 跳出循环
* continue 跳过循环
* return 返回值并结束方法
* 方法命名
* 1.见名知义
* 2.符合驼峰命名法
* */
public int max(int a, int b) {
return a > b ? a : b; // 三元表达式
}
}
静态方法与非静态方法
-
静态方法 —与类同时加载
-
非静态方法 -----类实例化之后才存在
-
静态方法可以通过 类名.方法名() 的方式直接调用
-
非静态方法则必须要实例化之后才能调用
package com.oop.demo;
public class Demo2 {
/*
* 静态方法与非静态方法
*
* 静态方法 --- 与类同时加载
*
* 非静态方法 ----- 类实例化之后才存在
*
* */
public void mA(){
mB();
}
public void mB(){
mC();
}
public static void mC(){
// mB(); 报错
}
public static void mD(){
mC();
}
}
package com.oop.demo;
public class Demo3 {
public static void main(String[] args) {
Demo2.mC();
// Demo2.mA();报错
}
}
值传递与引用传递
package com.oop.demo;
public class Demo4 {
private int age;
public static void main(String[] args) {
// 值传递
int a = 1;
System.out.println(a); // 1
add(a);
System.out.println(a); // 1
//引用传递
Demo4 demo4 = new Demo4();
demo4.age = 1;
System.out.println(demo4.age); //1
add(demo4);
System.out.println(demo4.age); //11
}
public static void add(Demo4 demo4) {
demo4.age += 10;
}
public static void add(int i) {
i = 10;
}
}
- Java的参数传递是值传递的
- 引用传递的本质还是值传递
- 对象的本质是在堆内存中创建了一个空间,在这个空间里存储着类的属性和方法
this与new关键字
- this关键字是占位符,在类中指的是具体的实例对象
- new关键字用来创建对象,在堆内存中申请内存空间
- 一个类即使什么都不写,它也会有一个默认的构造方法
package com.oop.demo;
public class Students {
String name;
int age;
int height;
int weight;
public void study() {
// this关键字,在这里指具体实例对象
System.out.println(this.name+"在学习");
}
}
package com.oop.demo;
public class Demo5 {
public static void main(String[] args) {
// 一个项目中只有一个main方法,它是程序的入口
Students xiaoMing = new Students(); //实例化对象
Students xiaoHong = new Students(); //实例化对象
xiaoHong.name = "小红";
xiaoMing.name = "小明";
xiaoMing.study();
xiaoHong.study();
}
}
构造器解析
-
构造器的作用
- 创建对象
- 属性初始化
-
构造器的本质是一个没有返回值类型的方法,也叫构造方法
-
当使用new关键字时必须要有构造器
-
如果没有定义构造器系统会自动的给这个类分配一个无参构造器
-
但是,一但定义了有参构造,无参构造就必须要定义才能使用,否则会报错!
-
构造器也可以有多个,系统会根据参数不同自动匹配对应的构造器
package com.oop.demo;
public class Demo6 {
String name;
int age;
public static void main(String[] args) {
Demo6 demo6_1 = new Demo6("test");
Demo6 demo6_2 = new Demo6(10);
Demo6 demo6_3 = new Demo6("test2",10);
// Demo6 demo6$= new Demo6(); // 报错
}
public Demo6(int age) {
this.age = age;
}
public Demo6(String name, int age) {
this.name = name;
this.age = age;
}
public Demo6(String name) {
this.name = name;
}
}
封装
-
我们程序设计要追求 “高内聚,低耦合”
- 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅暴露少量的方法给外部使用。
-
封装
- 数据隐藏
- 通常禁止直接访问一个对象中的数据实际表示,而应该通过操作接口来访问,这称为信息隐藏。
- 属性私有,通过get/set来访问
package com.oop.demo.demo6;
public class Person {
// 属性私有化 用private来修饰
/*
* 1.提高程序安全性,保护数据
* 2.隐藏代码实现细节
* 3.统一接口
* 4.增加系统的可维护性
* */
private String name;
private int age;
private String gender;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if (age > 120 || age < 0) {
// 过滤不合法数据
this.age = 3;
} else {
this.age = age;
}
}
public void setGender(String gender) {
if (!gender.equals("男") && !gender.equals("女")) {
// 过滤不合法数据
this.gender = "未知";
} else {
this.gender = gender;
}
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getGender() {
return gender;
}
}
package com.oop.demo.demo6;
public class Demo1 {
public static void main(String[] args) {
Person xiaoMing = new Person();
Person xiaoHong = new Person();
// xiaoMing.name = "小明"; // 报错,属性私有化不允许外部直接访问
xiaoMing.setName("小明");
xiaoMing.setGender("男");
xiaoMing.setAge(666);
xiaoHong.setName("小红");
xiaoHong.setGender("???");
xiaoHong.setAge(18);
System.out.println(xiaoMing.getName());
System.out.println(xiaoMing.getGender());
System.out.println(xiaoMing.getAge());
System.out.println("================");
System.out.println(xiaoHong.getName());
System.out.println(xiaoHong.getGender());
System.out.println(xiaoHong.getAge());
}
}
继承
-
继承的本质是对类的抽象,从而实现世界更好的建模。
-
extends 的意思是扩展,子类是父类的扩展
-
Java中类只有单继承,没有多继承!!!!
-
子类会从父类继承所有的属性和方法但是没有权限访问父类中私有的属性或方法,子类也可以有自己独有的属性和方法。
-
继承是类与类之间的关系。除此之外,类与类之间的关系还有依赖关系、组合、聚合等。
-
继承关系中的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用extends关键字来表示
-
父类和子类之间有 is 的关系
-
例: Person(人类)—> Student(学生类) < 学生 is 人>
-
例 : Person(人类)—> Teacher(老师类) < 老师 is 人>
-
例: Teacher(老师类) —> MathTeacher(数学老师类) <数学老师 is 老师>
-
package com.oop.demo.demo6;
//Student is Person
public class Student extends Person {
private int studentNumber;
public void study() {
System.out.println(this.getName() + ":好好学习,天天向上");
}
public void setStudentNumber(int studentNumber) {
this.studentNumber = studentNumber;
}
public int getStudentNumber() {
return studentNumber;
}
}
package com.oop.demo.demo6;
// Teacher is Person
public class Teacher extends Person {
private String subjects;
private int teacherNumber;
public void teach(){
System.out.println(this.getName()+":身为人师,教书育人");
}
public void setSubjects(String subjects) {
this.subjects = subjects;
}
public void setTeacherNumber(int teacherNumber) {
this.teacherNumber = teacherNumber;
}
public String getSubjects() {
return subjects;
}
public int getTeacherNumber() {
return teacherNumber;
}
}
package com.oop.demo.demo6;
//MathTeacher is Teacher
public class MathTeacher extends Teacher {
private String higherMathematics;
public void teachMath(){
System.out.println(this.getName()+":我会教数学,我是数学老师");
}
public String getHigherMathematics() {
return higherMathematics;
}
public void setHigherMathematics(String higherMathematics) {
this.higherMathematics = higherMathematics;
}
}
package com.oop.demo.demo6;
public class Demo2 {
// main 方法
public static void main(String[] args) {
Person person = new Person(); // 人
Student student = new Student(); // 学生
Teacher teacher = new Teacher(); // 老师
MathTeacher mathTeacher = new MathTeacher(); // 数学老师
person.setName("夏娃");
person.setAge(999);
person.setGender("男");
// ==================================
student.setName("小明");
student.setAge(18);
student.setGender("男");
student.setStudentNumber(9527);
student.study();
// ==================================
teacher.setName("王强");
teacher.setAge(29);
teacher.setGender("男");
teacher.setSubjects("语文");
teacher.setTeacherNumber(1452);
teacher.teach();
// ==================================
mathTeacher.setName("小微");
mathTeacher.setAge(24);
mathTeacher.setGender("女");
mathTeacher.setSubjects("数学");
mathTeacher.setTeacherNumber(54188);
mathTeacher.teach();
mathTeacher.teachMath();
}
}
- Object类是所有类的祖先类
-
修饰符:public 公共的,private 私有的,protected 受保护的
-
我们可以通过 super. 属性 或 方法 来访问父类的属性或方法,但是私有的东西无法被继承,所以子类无法访问私有属性或方法。
-
super注意点
- super调用父类的构造方法,必须放在构造方法的第一个
- 在子类构造器被调用时会自动调用父类的构造器,所以如果父类中如果定义了有参构造,而没有定义无参构造,则子类中将不再有无参构造。
- super只能出现在子类的方法或者构造方法中!
- this和super不能同时调用构造方法!
-
super & this
-
代表对象不同
- this代表本身的这个对象
- super代表父类对象的应用
-
前提
- this:没有继承也可以使用
- super只能在有继承条件才可以使用
-
构造方法
- this() ; 是本类构造
- super(); 是父类构造
-
方法的重写
-
方法的重写需要具备继承关系
-
一定是由子类重写父类的方法
-
参数列表必须相同,否则就是方法的重载而不是重写
-
修饰符只能扩大不能缩小!! public >protected >Default > priavte
-
抛出的异常可以缩小但不能扩大!
package com.oop.demo.demo7;
public class A {
public static void test1() {
System.out.println("A==>test1 静态方法");
}
public void test2() {
System.out.println("A==>test2 实例方法");
}
}
package com.oop.demo.demo7;
public class B extends A {
public static void test1() {
System.out.println("B==>test1 静态方法");
}
@Override // 注解,有功能的注释 Override 重写
public void test2() {
System.out.println("B==>test2 实例方法");
}
}
package com.oop.demo.demo7;
public class Demo1 {
public static void main(String[] args) {
/*
* 静态方法和非静态方法区别很大!
* 静态方法: 静态方法只跟类的类型有关
*
* */
// A类是B类的父类
A a = new B(); // 父类的引用指向子类,子类重写父类的方法
B b = new B();
a.test1(); // A==>test1 静态方法
a.test2(); // B==>test2 实例方法
b.test1(); // B==>test1 静态方法
b.test2(); // B==>test2 实例方法
}
}
多态
- 多态编译:类型:可扩展性
- 即统一方法可以根据
package com.oop.demo.demo8;
public class demo8 {
public static void main(String[] args) {
/*
* 一个对象的实际类型是确定的
*
* 但是可以指向的引用类型就不确定了:父类的引用指向子类
* */
Person person = new Person();
Person student = new Student(); // 实际类型Person 引用类型Student
Student student$ = new Student();
person.setName("人");
student.setName("学生A");
// student.Study(); // 报错,Person 没有study方法,父类可以指向子类,但不能访问子类独有的方法
((Student) student).study(); // 类型转化之后可以使用
student$.setName("学生$");
student$.study();
/*
* 有没有可以调用只用看左边类型,左边的类中有这个方法就可以调用
* */
}
}
- 多态注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 类型转换异常 —> ClassCastException
- 存在继承关系,方法被重写,父类引用指向子类 Parent fahter = new Son( );
- static , private , final 修饰的方法不能被重写
instanceof 和类型转换
- instanceof 关键字可以判断一个对象的类型,是不是某个类的实例
package com.oop.demo.demo9;
public class demo9 {
// instanceof 判断对象是否是某个类的实例
public static void main(String[] args) {
Object student = new Student();
Teacher teacher = new Teacher();
Student student$ = new Student();
System.out.println(student instanceof Object); //true
System.out.println(student instanceof Person); //true
System.out.println(student instanceof Student); //true
System.out.println(student instanceof Teacher); //false
System.out.println(student instanceof String); //false
System.out.println("=============================");
System.out.println(student$ instanceof Object); //true
System.out.println(student$ instanceof Person); //true
System.out.println(student$ instanceof Student); //true
// System.out.println(student$ instanceof Teacher); //编译报错
// System.out.println(student$ instanceof String); //编译报错
System.out.println("=============================");
System.out.println(teacher instanceof Object); //true
System.out.println(teacher instanceof Person); //true
// System.out.println(teacher instanceof Student); //编译报错
System.out.println(teacher instanceof Teacher); //true
// System.out.println(teacher instanceof String); //编译报错
}
}
-
类型转换(引用类型)
- 低--------------------------------------->高 自动转换 ,子类转父类,可能会丢失子类的一些方法,【子类转父类我们称之为向上转型】
- 高--------------------------------------->低 强制转换,父类转子类【父类转子类我们称之为向下转型】
-
类型转换方便方法的调用,减少重复代码。