6_面向对象
1 什么是面向对象?
面向过程 & 面向对象
Java 的核心思想就是 OOP (OO object-oriented就是面向对象)
- 面向过程思想
- 步骤清晰简单,第一步做什么,第二步做什么...
- 面向过程适合处理一些比较简单的问题
- 面向对象思想
- 物以类聚,分类的思维模式,思考问题,首先会想解决问题需要哪些分类,然后对这些分类进行单独思考。最后,再对某个分类下的细节进行面向对象过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
- 总结:对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍需要面向对象过程的思路去处理。
什么是面向对象?
- 面向对象编程(OOP)
- 面向对象的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据。
- *抽象 (抽“像”)
- 三大特性:
- 封装
- 继承
- 多态
- 从认识论的角度考虑是先有对象,后又类。对象,是具体的事物。类,是抽象的,是对 对象的抽象
- 从代码运行角度考虑先有类后又对象。 类是对象的模板。
2 回顾方法的定义
去看方法的定义,这里就不写了。
为什么需要public static void main(String[] args)这个方法?
答:在未分类中详细说了。去看看。
3 回顾方法的调用
去看方法的调用,主义静态方法,非静态方法,调用的异同。
什么是类的实例化?
类是指:描述一种事物的定义,是个抽象的概念
实例指:该种事物的一个具体的个体,是具体的东西
打个比方:
“人”是一个类。“张三”是人类的一个具体例子
在编程时也是同样的道理,你先自己定义一个“类”,当你需要用时,用“类”的定义来创造一个具体的例子。
用类的定义来创建一个实例,就叫做类的实例化。
// 对象类型 对象名 = 对象值
Student student = new Student();
匿名对象来调用: new Student().say()
匿名对象
匿名:简单的说就是没有名字的对象
匿名优点:节省为 ‘ 对象地址 ’ 开辟的空间
正常写法:
Student stu = new Student();
String name = stu.getName ;
new Student() 对象的名字为stu;
> 匿名写法:
> 1. Student[] stu = new Student[100];
> stu[0] = new Student();
表示的是stu数组的第一个元素为一个Student的对象,并且 new Student() 是没有名字的。
2 直接用对象调用方法
new studnet().getName;
>
铺垫:
package pers.kang.demo01;
public class E {
public static void main(String[] args) {
Person per = new Person();
System.out.println(per.name); // null
change(per); // 给方法传入参数
System.out.println(per.name); // 小明
}
public static void change(Person person) { // 把 per 堆空间使用权,交给person,所以person可以调用属性
// person 是一个对象:指向的是---> Person person = new Person(); 是一个具体的人
person.name = "小明";
}
}
class Person {
String name; // null
}
4 类与对象的创建
4.1 类 和 对象是什么?
- 类是一种抽象的数据类型,它是对一类事务整体描述/定义,但是并不能代表某一个具体的事物
- 动物,植物,手机,电脑
- Person类、Pet类 、Car类 等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
- 对象是抽象的概念的具体实例
- 张三 就是人的具体实例,张三 的 旺旺 就是狗的具体实例。
- 能够体现出特点,展现出功能的是具体实例,而不是一个抽象的概念。
4.2 创建和初始化对象
-
使用 new 关键字创建对象
-
使用 new 关键字创建的时候,除了分配内存空间之外,还会给创建好的对象 进行默认的初始化,以及对类中构造器的调用
// 一个项目应该只存在一个 main 方法
public class Application {
public static void main(String[] args) {
// 类:抽象的,实例化
// 类实例化后会返回一个自己的对象! Student xiaoming = new Student();
// student对象就是一个Student 类具体的实例! 比如上面这个,嘿嘿!
Student student = new Student();
student.name = "小明明";
student.age = 3;
System.out.println(student);
student.study();
}
// 学生类
public class Student {
// 属性: 字段
String name; // 我们没有赋值的时候,就是null
int age; // 默认: 0
public void study(){
System.out.println(this.name+",学习ing");
}
5 构造器详解
类中的构造器也称为构造方法,是在进行创建对象名的时候必须调用的。并且构造器有一下两个特点:
-
- 必须和类的名字相同(如果一个源文件中有多个类,那么构造器必须与公共类同名)
- 必须没有返回类型,也不能写 void
- 每个类可以有一个以上的构造器 (我们查看了反编译后的字节码文件,可以看到,一个类即使什么都不写,它也会存在一个方法,就是构造方法)
- 构造器可以有0个、1个或1个以上的参数
- 构造器总是伴随着new操作一起调用
- 很重要!!!
作用:
- 使用 new 关键字,本质是在调用构造器 (可以这样理解,通过new关键字去调用构造方法)
- 初始化对象的值
注意点:
-
一旦定义了有参构造,想使用无参,无参就必须显示构造
-
注意:不管有没有用,把无参构造带上,肯定不会报错(规范)
可以同时有无参构造和有参构造吗?
可以的,都是在构造的时候被调用。
如果在创建对象时不写参数,调用的就是无参的构造方法。可是如果你写的有有参的构造方法,而没有无参的构造方法,那么再“创建对象时不写参数”就会报错,程序会认为你知道该怎么做。
如果构造方法有参数,在创建对象时传入了参数,那么就会调用此方法,这一点和重载类似。
6 创建对象内存分析
(和类一起加载)
-
类和方法的定义:储存在堆区的方法区
-
定义的静态方法区会储存 static 性质的方法 和数据类型
-
定义对象名,储存在栈区。
-
new 会在堆区开辟一个专属的空间,此时会给属性赋值默认值(这里看看 java 中 8 个基本数据类型的默认值),并储存到堆区。

7 简单小结类与对象
1、类与对象
类是一个模板: 抽象 ; 对象是一个具体的实例
2、方法
定义、调用
3、 对应的引用
引用类型:基本类型(8)
对象是通过引用来操作的: 栈--->堆
4、 属性,字段 Field 成员变量
默认初始化:
数字: 0, 0.0
char: u0000
boolean:false
引用:null
修饰符 属性类型 属性名 = 属性值
5、 对象的创建和使用
- 必须使用 new 创建对象,构造器 Person xiaoming = new Person();
- 对象的属性, xiaoming.name;
- 对象的方法:person.shout();
6、类:
静态的属性 属性
动态的行为 方法
类 = 属性 + 方法
8 封装
- 该露的露,该藏的藏
- 我们程序设计的要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成;低耦合:仅暴露少量的方法给外部使用。
- 封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
- 记住这句话就够了:属性私有,get / set,设置 set 成员变量存取限制
package pers.kang.demo04;
// private:私有
/*
1、提高程序的安全性,保护数据
2、隐藏代码的实现细节
3、统一接口
4、系统可维护增加了
一般情况是不会对 getter / setter 方法重载的
大部分对构造器进行重载
*/
public class Student {
// 属性私有
private String name; // 名字
private int id; // 学号
private char sex; // 性别
private int age; // 年龄
// 提供一些可以操作这些属性的方法
// 提供一些 public 的 get 和 set 方法
// get: 获取这个数据 ;
public String getName(){
return this.name;
}
// set: 给这个数据设置值
public void setName(String name){
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 & age < 120){
this.age = age;
}else {
this.age = 3;
}
}
/*
大多数情况我们只对属性封装,方法用的比较少
*/
// 学习()
// 睡觉()
}
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("小明");
System.out.println(s1.getName());
s1.setAge(-1); // 不合法的
System.out.println(s1.getAge());
}
}
9 继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- extends 的意思是 “扩展”。 子类是父类的扩展。
- Java 中类只有单继承,没有多继承! (一个类可以被多个类继承,但是不能继承多个类)
- 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖,组合,聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类。子类继承父类,使用关键字extends来表示。
- 子类和父类之间,从意义上讲,应该具有 “is a ” 的关系。
public protected default private
继承是一个宏观的把握,封装实现细节,多态也和继承有关系。所以很重要
子类继承父类就会继承父类的全部方法;
子类不能继承父类私有的东西,父类私有的东西,子类无法继承。 但是可以提供public 的 getter/setter 方法,子类就可以继承并且使用了。
在 java 中所有的类,都默认的直接或间接的继承 Object 类。
Ctrl + H :打开”继承树“
// 父类
public class Person {
public int money = 100_0000_000;
public void say() {
System.out.println("说---");
}
}
// 子类 学生 is 人
public class Student extends Person {
}
// 测试类
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
System.out.println(student.money);
}
}
10 this 和 Super 详解
this 关键字
1、指代当前对象 (常用于对象的比较操作,就是比较对象是否一样)
2、指代当前类
3、 指代本类构造方法 this(): 表示当前类的构造方法,只能放在首行
super 关键字
- 只能指代父类对象
- 指代父类的构造方法,只能放在首行
注意
-
子类必须通过 super 关键字调用父类有参数的构造函数
-
使用 super 调用父类构造器的语句必须是子类构造器的第一条语句
-
super 必须只能出现在子类方法或者构造方法中
super 和 this 不能同时调用构造方法,因为他俩都要放在首行,会冲突,总会有一个报错
如果子类构造器没有显式地调用父类的构造器,则将自动调用父类的默认(没有参数)的构造器(在子类构造中隐藏了 super())。
如果父类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用父类的构造器,则java编译器将报告错误
Ctrl + F 在类中搜索
// 父类
public class Person {
protected String name = "小明明";
// 私有的东西无法被继承
public void print() {
System.out.println("Person");
}
}
//子类
public class Student extends Person {
private String name = "小明";
public void print() {
System.out.println("xiaoming");
}
public void test(String name) {
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void test1() {
print(); // Student
this.print(); // Student
super.print(); // Person
}
}
// 测试类
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("小哈");
student.test1();
}
}
11 方法重写
重点---->> 多态
// 重写都是方法的重写,和属性无关,且针对的是非静态方法,和静态无关
重写:需要有继承关系,子类重写父类的方法!
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大,但不能缩小: public > protected > default > private
- 重写可能会抛出异常,范围,可以被缩小,但不能扩大:ClassNotFoundException---> Exception (小)
子类继承父类后,重写父类的方法,子类的方法和父类必须一致,方法体不同!
那 为什么要重写?
- 父类的功能,子类不一定需要,或者不一定满足
- Alt+insert; override;
方法重载和重写是不同的概念,主要有以下区别:
1、首先是含义不同
1)方法重载是在同一个类中,声明多个同名方法,通过参数列表来区分不同的方法,与参数列表的数量、类型和顺序有关,与修饰符和返回值类型以及抛出异常类型无关
2)方法重写的前提是发生在具有继承关系的两个类之间,方法重写有以下规则:
a.参数列表必须保持一致
b.返回值类型必须保持一致
c.方法名必须保持一致
d.重写方法的访问权限范围必须大于等于父类方法
e.重写方法的抛出异常类型范围不能大于父类方法
2、方法的重载和重写的作用不同
重载:在一个类中为一种行为提供多种实现方式并提高可读性
重写:父类方法无法满足子类的要求,子类通过方法重写满足需求
实例:
重载:构造方法的重载、println() 方法重载
重写:Object 类的 toString()、equals()、hashCode() 等都可以被子类重写
我们用图来看一下:

12 多态
12.1 什么是多态?
-
即同一个方法可以根据发送对象的不同而采用多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多。(父类,有关系的类)
-
动态编译:类型 可扩展性
12.2 多态存在的条件
-
有继承关系
-
子类重写父类方法
-
父类引用指向子类对象
-
注意: 多态是方法的多态,属性没有多态
*类型转换异常:ClassCastException 看到这个我们就知道,子父类出现了问题
public class Application {
public static void main(String[] args) {
// 一个对象的实际类型是确定的
// new Student();
// new Person();
// 可以指向的引用类型就不确定了,父类的引用指向子类
Student s1 = new Student(); // Student 能调用的调方法都是自己的或者继承父类的
//父类的引用指向子类对象
Person s2 = new Student(); // Person 父类型,可以指向子类,但是不能调用子类独有的方法,如果子类没有重写,调用父类的方法,因为子类继
//承了父类全部的方法, 子类重写了父类的方法,则调用子类重写的方法。
Object s3 = new Student();
// 对象能执行那些方法名主要看对象左边的类型,和右边关系不大
s2.run();
s1.eat();
((Student)s2).eat();
}
}
13 instanceof 和 类型转换
作用:用来测试一个对象是否为一个类的实例
boolean result = obj instanceof Class
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
我们新建一个父类 Person.class,然后在创建它的一个子类 Man.class
public class Person {}
Man.class
public class Man extends Person{ }
测试:
Person p1 = new Person();
Person p2 = new Man();
Man m1 = new Man();
System.out.println(p1 instanceof Man); //false
System.out.println(p2 instanceof Man); //true
System.out.println(m1 instanceof Man); //true
注意第一种情况, p1 instanceof Man ,Man 是 Person 的子类,Person 不是 Man 的子类,所以返回结果为 false。
类型转换:
//
Student studnet = new Studnet;
高转低
Person per = student; // 父类引用指向子类对象
1、父类引用只想子类对象
2、把子类转换为父类,向上转型
3、把父类转换为子类,向下转型; 强制转换
4、方便方法的调用,减少重复的代码。
14 static 关键字
在同一个类中:
- 对于静态变量,静态和非静态方法都可以直接调用。
- 对于非静态变量,非静态可以直接调用,静态只能通过对象来调用它。
在不同类中:无论调用时非静态还是静态,如果被调用的变量是:
- 静态变量:类名.属性名调用
- 非静态变量:只能通过对象才可以调用它。
还有静态方法,非静态方法的调用,去方法.md去看
package pers.kang.demo05;
import com.sun.media.sound.SoftTuning;
public class Application {
//2、
{
System.out.println("匿名代码块");
}
//1、 只执行一次,且最先执行,赋初值
static {
System.out.println("静态代码块");
}
//3、
public Application() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Application a = new Application();
System.out.println("===========================");
Application a1 = new Application();
}
}
静态代码块
匿名代码块
构造方法
===========================
匿名代码块
构造方法
Process finished with exit code 0
静态导入包
package pers.kang.demo05;
// 静态导入包
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
System.out.println(random());
}
}
15 抽象类
-
abstract 修饰符可以用来修饰方法,也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类;
-
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
-
抽象类,不能使用 new 关键字来创建对象,它是用来让子类继承的。
-
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
//约束 有人帮我们实现~
// abstract ,抽象方法,只有方法名字,没有方法的实现
public abstract void doSomething();
//1、它的特点,其实它没有什么特点,因为它太抽象了
// 不能 new 这个抽象类,只能靠子类去实现它:约束!
//2、抽象类可以写普通方法
//3、 抽象方法必须写在抽象类中,抽象的抽象,约束
// 为什么要用抽象类呢? 因为它可以提高开发的效率,节省代码的书写。
}
// 抽象类的所有方法,继承了它的子类,都必须要实现它的方法 除非它的子类也是抽象类,那就要它的子子类去实现了
public class A extends Action {
@Override
public void doSomething() {
}
}
16 接口的定义 与 实现
类很抽象,抽象类更加抽象,接口比抽象类还抽象!
它没有构造方法,不能 new,也就是不能实例化
-
普通类:只有具体实现
-
抽象类: 具体实现和规范(抽象方法)都有!
-
接口:只有规范!自己无法写方法, 专业的约束! 约束和实现分离:面向接口编程
-
接口就是规范,定义的是一组规则,体现了现实世界中“ 如果你是.....则你必须能.....” 的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须干掉坏人;如果你是坏人,则必须不干好事。
-
接口的本质是契约,就像我们人间的法律一样。制定好,大家都要遵守。
-
OO(面向对象) 的精髓,是对 对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备抽象能力的语言(比如C++ , java, c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
我的解释:
接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成。接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)
接口的特点:
就像一个类一样,一个接口也能够拥有方法和属性,但是在接口中声明的方法默认是抽象的。(即只有方法标识符,而没有方法体)。
- 接口指明了一个类必须要做什么和不能做什么,相当于类的蓝图。
- 一个接口就是描述一种能力,比如“运动员”也可以作为一个接口,并且任何实现“运动员”接口的类都必须有能力实现奔跑这个动作(或者implement move()方法),所以接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
- 如果一个类实现了一个接口中要求的所有的方法,然而没有提供方法体而仅仅只有方法标识,那么这个类一定是一个抽象类。(必须记住:抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类)
为什么要用接口:
-
接口被用来描述一种抽象。
-
因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。
-
接口也被用来实现解耦。
-
接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?
答:原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是final,public,static的。
关于接口的几个重点:
-
我们不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的,这样怎么可能产生具体的实例呢?
答:我们可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。(实际上就是使用了Java中多态的特性)
声明类的关键字是 class, 声明接口的关键字是 interface
// 抽象的思维~ JAVA 架构师
// 定义的关键字是:interface 接口都需要有实现类
public interface UserService {
//接口中的所有定义方法其实都是抽象的 public abstract 隐藏了,没有写
// 属性默认的也是一个常量,
public static final int age = 99;
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface TimeService {
void timer();
}
// 抽象类: extend 单继承 就有局限性了
// 为啥会爆红呀? 还没有实现接口中的方法 因为实现接口要实现里面的所有规范
// 实现了接口的类,就要重写接口的中的方法,少一个都不行
// 接口可以实现多继承,
public class UserServiceImpl implements UserService , TimeService {
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
17 N 种内部类
17.1 什么是内部类?
定义: 将一个类定义在一个类或者一个方法里面,这样的类称着内部类
- 内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,而A类相对于B类来说就是外部类了。
17.2 内部类的种类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
本文来自博客园,作者:走马!,转载请注明原文链接:https://www.cnblogs.com/zou-ma/p/16019090.html
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术