面向对象编程(OOP)
1.什么是面向对象
(1).面向过程思想
- 步骤清晰简单,第一步,第二步
- 适合一些较为简单的问题
(2).面向对象思想
- 分类的思想,物以类聚
- 适合复杂的问题
(3).宏观把握,面向对象。微观操作,面向过程。
(4).面向对象
- 面向对象编程(Object-Oriented Programming,OOP)
- 本质:以类的方式组织代码,以对象组织(封装)数据。
- 抽象
- 三大特性:封装,继承,多态
从认知角度:先有对象后有类。对象是具体的事物,类是对对象的抽象
从代码运行角度先有类后有对象。类是对象的模板
2.回顾方法的定义
package oop;
import java.io.IOException;
// Demo01 类
public class Demo01 {
// main 方法
public static void main(String[] args) {
}
/*
修饰符 返回值类型 方法名(。。。){
方法体
return 返回值;
}
*/
public String sayHello(){
return "hello,world";
}
public int max(int a,int b){
return a>b? a : b;
// return 结束方法
// break 跳出循环
}
public void print(){
return;
}
// 抛出异常
public void redFile(String file) throws IOException{
}
}
3.方法的调用
package oop;
public abstract class Demo02 {
// 静态方法 static
// public static void main(String[] args) {
// Student.say();
// }
// 非静态方法
// 实例化这个类 new
// 对象类型 对象名 = 对象值;
public static void main(String[] args) {
Student student = new Student();
student.say();
}
// 和类一起加载的
public static void a(){
// b();
}
// 类实例化之后才存在的
public void b(){
}
}
(1).形参,实参
package oop;
public class Demo03 {
public static void main(String[] args) {
Demo03 demo03 = new Demo03();
// 形参和实参的类型要对应!
int add = demo03.add(1, 2);
System.out.println(add);
}
public int add(int a,int b){
return a+b;
}
}
(2).值传递和引用传递
- 值传递
package oop;
// 值传递
public class Demo04 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);
Demo04.change(a);
System.out.println(a);
}
// 返回值为空
public static void change(int a){
a = 10;
}
}
- 引用传递
传递对象,类似c语言的指针,class类似c语言的struct和typestruct
package oop;
// 引用传递:对象
public class Demo05 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Demo05.change(person);
System.out.println(person.name);
}
public static void change(Person a){
a.name = "thj";
}
}
// 定义了一个类,有一个属性:name
class Person{
String name; // null
}
4.类与对象的创建
类是一种抽象数据类型
对象是抽象概念的具体实例
(1).创建和初始化对象
使用new关键词创建对象
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及类中构造器的使用。
package oop;
// 一个项目只存在一个main方法
public class Application {
public static void main(String[] args) {
// 类是抽象的需要实例化
// 类实例化后会返回一个自己的对象
// student对象就是Student对象的实例
Student xiaoming = new Student();
Student xh = new Student();
xiaoming.age = 3;
xiaoming.name = "小明";
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
xiaoming.study();
xh.name = "小红";
xh.age = 3;
System.out.println(xh.age);
System.out.println(xh.name);
xh.study();
}
}
(2).构造器详解
构造器又称构造方法,特点:
- 必须和类的名字相同
- 必须没有返回类型,也不写void
- 在类产生时就有了
- 可以初始化一些属性
- 写有参构造,必须显示定义无参构造
- alt+insert
package oop;
public class Person {
// 一个类即使什么都不写,也会有一个方法(构造方法)
// 显示的构造器
String name;
// 实例化初始值
// 使用new关键字,必须有构造器,本质在调用构造器
public Person(){
}
// 有参构造:一旦定义了有参构造,无参就必须显示定义(可以留空)
public Person(String name){
this.name = name;
}
// alt+insert 生成构造器
}
/*
package oop;
// 一个项目只存在一个main方法
public class Application {
public static void main(String[] args) {
// new实例化了一个对象
Person person = new Person("thj");
System.out.println(person.name);
}
}
构造器:
1.和类名相同
2.无返回值和void
作用:
1.new本质在调用构造器
2.初始化对象的值
注意:
定义有参构建之后想要用无参构建,要把无参构建显示的定义
alt+insert
this. = ;
*/
有点类似python的_init_()函数
5.创建对象内存分析
- 栈中存放main()方法和引用变量名
- 堆中放为变量开辟的空间,或者说实例化的类方法
- 栈中的引用变量名指向堆中的空间
- 方法在方法区,还有常量池,静态方法区(和类一起加载)
6.类小结与对象
- 类是模板,方法是调用
- 引用类型:除了八大基本类型
- 对象通过引用来操作:栈——>堆
- 属性:成员变量,默认初始化
- 方法定义和调用
- 必须使用new关键字创造对象,构造器
- 对象的属性 xx.xxx;
- 对象的方法 xx.xxx();
- 类:静态的属性,动态的行为
- 封装,继承,多态
7.封装
(1).该露的露,该藏得藏
程序设计追求”高内聚,低耦合“。高内聚即类的内部数据操作细节自己完成不允许外部干涉。低耦合:仅暴露少量的方法给外部使用。
(2).封装
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
(3).记住一句话:
属性私有,get/set
package oop;
// 类 private:私有
public class Student2 {
// 属性私有
// 名字
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;
}
//alt+insert自动生成get/set方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>120 || age<0){ // 不合法的
this.age = 3;
}else {
this.age = age;
}
}
}
//package oop;
//// 一个项目只存在一个main方法
//public class Application {
// public static void main(String[] args) {
// Student2 s1 = new Student2();
// s1.setName("thj");
// // 方法名 参数列表
// System.out.println(s1.getName());
// s1.setAge(999); // 不合法的
// System.out.println(s1.getAge());
//
// }
//}
/*
封装的好处
1.提高代码安全性,保护数据
2.隐藏代码的实现细节
3.同一接口
4.提高系统可维护性
*/
8.继承
(1).本质
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
(2).extends
意思是”扩展“。子类是父类的扩展
(3).
java类只有单继承,没有多继承。一个子类只继承一个父类,一个父类下可以有多个子类
- 继承是类与类的关系。还有依赖,组合,聚合等。
- 继承关系的两个类,一为子类(派生类),二为父类(基类)。子类继承父类,使用关键词extends表示。
- 子,父类之间,从意义上讲存在”is a“的关系。
父类:
package oop.Extends;
// 在java中,所有的类都直接或者间接继承Object类
// Person 人 父类
public class Person { /*extends Object*/
// public:公共的
// protected:受保护的
// default:默认的
// private:私有的
private int money = 10_0000_0000;
public void say() {
System.out.println("说了一句话");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
/*
package oop;
import oop.Extends.*;
import oop.Extends.Person;
import oop.Extends.Student;
// 一个项目只存在一个main方法
public class Application {
public static void main(String[] args) {
// Student student = new Student();
// student.say();
// System.out.println(student.getMoney());
Person person = new Person();
}
}
*/
子类:
package oop.Extends;
// 学生 is a 人 : 派生类,子类
// 子类继承了父类,会拥有父类的全部方法
public class Student extends Person{
// ctrl+h 打开继承树
}
9.Super详解
父类无参构造器没写,子类就继承不了,子类就没有无参构造器,但是可以继承父类的有参构造器
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
super与this比较
(1).代表的对象不同:
- this:本身调用者的对象
- super:代表父类对象的应用
(2).前提:
- this:没有继承也可以使用
- super:只能在继承条件下才能使用
(3).构造方法
- this()本类的构造
- super()父类的构造
package oop.Extends;
// 学生 is a 人 : 派生类,子类
// 子类继承了父类,会拥有父类的全部方法
public class Student extends Person{
// ctrl+h 打开继承树
private String name = "jiutao";
public Student(){
// 隐藏代码:调用了父类的无参构造。
super("hello");// 调用父类的构造器,必须放在第一行,但是默认好了。
System.out.println("Student无参继承了");
}
// public Student(String name){
// this.name = name;
// }
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void print(){
System.out.println("Student");
}
public void test1(){
print();
this.print();
super.print();
}
}
10.方法重写
重写:
需要继承关系,子类继承父类
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大:public>protected>default>private
- 抛出的异常:范围:可以缩小,但不能扩大
子类方法和父类必须一致,方法体不同!
为什么需要重写:
- 父类的功能子类未必需要,或者不一定满足!
- Alt + Insert :override;
package oop.Extends;
public class A extends B{
// 重写
@Override // 注解:有功能的注释!
public void test() {
System.out.println("A=>test()");;
}
}
package oop.Extends;
// 重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
package oop;
import oop.Extends.A;
import oop.Extends.B;
public class Application {
public static void main(String[] args) {
// 静态和非静态方法有很大区别!
// 方法的调用只跟左边,定义的数据类型有关
A a = new A();
a.test(); // A
// 父类的引用指向了子类
B b = new A(); // 子类重写了父类的方法
b.test(); // B
}
}
11.多态
(1).多态
- 动态编译:类型:可扩展性
- 即同一方法可以根据发送对象不同而采用多种不同的行为方式
(2).多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
(3).注意
多态是方法的多态,类没有多态性。
(4).注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 类型转换异常!ClassCastException!
- 存在关系:继承关系,方法需要重写,父类引用指向子类对象!Father f1 = new Son()
- static 方法,属于类,它不属于实例,不能重写
- final 常量;不能重写
- private 方法;不能重写
(5).instanceof和类型转换
- instanceof关键词(类型转换)引用类型,判断一个对象是什么类型。
- 子类引用父类的对象
- 把子类转换成子类,向上转型
- 把父类转化成子类,向下转换:强制转换
- 方便方法的调用,减少重复的代码,简洁
抽象:封装,继承,多态! 抽象类,接口。
package oop.DuoTai;
public class Person {
public void run(){
System.out.println("run");
}
}
package oop.DuoTai;
public class Student extends Person{
public void go(){
System.out.println("go");
}
}
package oop;
import oop.DuoTai.Person;
import oop.DuoTai.Student;
import oop.DuoTai.Teacher;
public class Application {
public static void main(String[] args) {
// 一个对象的实际类型是确定的
// new Student();
// new Person();
// 可以指向的引用类型就不确定了:父类的引用指向子类
// Student能用继承的和重写的
// Student s1 = new Student();
// Person父类型,可以指向子类,但是不能调用子类独有的方法
// Person s2 = new Student();
// Object s3 = new Student();
// 能执行那些方法注意看对象左边的类型,和右边关系不大
// s2.run(); // 子类重写父类的方法,执行子类的方法
// s1.run();
// ((Student) s2).eat();
// s1.eat();
// Object>Person>Student
// Object student = new Student();
// System.out.println(student instanceof Student);
// System.out.println(student instanceof Person);
// System.out.println(student instanceof Object);
// System.out.println(student instanceof Teacher);
// System.out.println(student instanceof String);
//
// System.out.println("=============");
//
// Person person = new Student();
// System.out.println(person instanceof Student);
// System.out.println(person instanceof Person);
// System.out.println(person instanceof Object);
// System.out.println(person instanceof Teacher);
// System.out.println(person instanceof String);编译报错!
// System.out.println("=============");
// Student S1 = new Student();
// System.out.println(S1 instanceof Student);
// System.out.println(S1 instanceof Person);
// System.out.println(S1 instanceof Object);
// System.out.println(S1 instanceof Teacher); 编译报错!
// System.out.println(X instanceof Y);能不能编译通过。
// 类型之间的转化:基本类型转换 高低64 32
// 类型之间的转换 父 子
// 高 低
// Person student = new Student();
// student转换为Student类型,可以使用其方法
// Student student1 = (Student) student;
// ((Student) student).go();
// ((Student) student).go();
// 子类转换为父类,可能会丢失一些方法
Student student = new Student();
student.go();
Person person = student;
}
}
12.static修饰符详解
(1).
修饰变量,方法,修饰过的可以直接通过类调用
package oop.keyword;
// static
public class Student {
private static int age; // 静态变量
private double score; // 非静态变量
public void run(){
}
public static void go(){
}
public static void main(String[] args) {
Student s1 = new Student();
go();
s1.run();
}
(2).
代码块,静态代码块
package oop.keyword;
public class Person {
int a;
// 2:赋初始值
{
// 代码块(匿名代码块)
System.out.println("匿名代码块");
}
// 1:只执行一次
static {
// 静态代码块
System.out.println("静态代码块");
}
// 3
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("=============");
Person person2 = new Person();
}
}
(3).
静态导入方法
package oop.keyword;
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class test {
public static void main(String[] args) {
System.out.println(random());
}
}
(4).补充
final修饰符修饰的类无法被继承
13.抽象类
abstract修饰符可以用来修饰方法也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么就是修饰类。
抽象类可以写普通方法,但是抽象方法必须在抽象类中
抽象的抽象:约束
package ChouXiang;
// abstract 抽象类:类 extends:单继承。 接口可以多继承
public abstract class Action {
// 约束-有人帮我们实现
// abstract ,抽象方法,只有方法的名字,没有方法的实现!
public abstract void doSomething();
// 1.不能new这个抽象类,只能靠子类去实现它:约束!
// 2.能写普通的方法
// 3.抽象方法必在抽象类中
}
package ChouXiang;
// 抽象类的所有方法,继承了它的子类,都必须实现它的方法
public class A extends Action{
@Override
public void doSomething() {
}
}
14.接口
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有!
接口:只有规范!自己无法写方法,专业的约束。约束和实现分类:面向接口编程。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是....则必须能.....”的思想。
接口的本质是契约
interface定义接口
作用 :
- 约束
- 定义一些方法,让不同的人实现
- 方法都是 public abstract
- 常量都是 public static final
- 接口不能实例化,接口没有构造方法
- implements可以实现多个接口
- 必须要重写接口中的方法
package oop.JieKou;
// 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);
}
package oop.JieKou;
// 抽象类:extend;
// 类 可以实现接口 implements 接口
// 实现接口的类,就需要重写接口中的方法
// 利用接口。实现多继承
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() {
}
}
package oop.JieKou;
public interface TimeService {
void timer();
}
15.内部类
内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
package oop.NeiBuLei;
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法。");
}
public static class Inner{
public void in(){
System.out.println("这是内部类的方法");
} // 获得外部类的私有属性,方法
}
// 一个java类中可以有多个class类,但只能有一个public类
// 局部内部类
public void method(){
class Inner{
public void in(){
}
}
package oop;
import oop.NeiBuLei.Outer;
public class Application {
public static void main(String[] args) {
// new
Outer outer = new Outer();
// 通过外部类来实例化内部类
// Outer.Inner inner = outer.new Inner();
// inner.in();
// inner.getID();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App