面向对象编程
面向对象编程(OOP)
什么是面向对象?
-
Java的核心思想就是OOP(Object-Oriented Programming)
-
类=属性+方法
-
面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据
-
抽象
-
三大特性:
- 封装
- 继承
- 多态
-
从认识论的角度:现有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象。
-
从代码运行的角度:现有类后有对象。类是对象的模板。
回顾方法及加深
- 方法的定义:
- 修饰符(例如public, static等...)
- 返回值类型
- break(跳出switch,结束循环)和return的区别
- 方法名:注意命名规范(首字母小写+驼峰原则);见名知意
- 参数列表:(参数类型 参数名)...
- 异常抛出
Demo:
package com.judy.oop;
//Demo01类
public class Demo01 {
//main方法
public static void main(String[] args) {
System.out.println(sayHello());
System.out.println(max(1,2));
}
/*
修饰符 返回值类型 方法名(...参数列表){
//方法体
return 返回值;
}
*/
//return 结束方法,返回一个结果(结果可能为空)
public static String sayHello() {
return "hello";
}
public static int max(int a, int b) {
return a>b?a:b; //三元运算符
}
}
-
方法的调用:
- 静态方法和非静态方法
![image-20251212200553830]()
-
形参和实参
package com.oop.demo01; public class Demo03 { public static void main(String[] args) { //实际参数和形式参数和类型要对应! int add=Demo03.add(1,2); System.out.println(add); } public static int add(int a, int b){ return a+b; } } -
值传递和引用传递(java本质上都是值传递)
![image-20251212205729723]()
-
this关键字
类与对象的创建
-
类与对象的关系:
-
类是一种抽象的数据类型,它是对某一类事物整体的描述/定义,但并不能代表某一个具体的事物
-
对象是抽象概念的具体实例
-
Demo:
package com.oop.demo02; //学生类 public class Student { //属性:字段 String name; //null int age; //0 //方法 public void study(){ System.out.println(this.name+"在学习"); } } /* public static void main(String[] args) { //类:抽象的,需要实例化 //类实例化后会返回一个自己的对象! //student对象就是一个Student类的具体实例! Student student = new Student(); student.name = "judy"; student.age = 23; System.out.println(student.name); System.out.println(student.age); } */
-
-
创建与初始化类:
-
使用new关键字创建对象
-
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化,以及调用类中的构造器
-
类中的构造器也称为构造方法,是在创建对象时必须调用的!构造器有以下两个特点:
1.必须和类的名字相同; 2.必须没有返回类型,也不能写void
-
Demo:
package com.oop.demo02; //java → class public class Person { String name; //一个类即使什么都不写,编译生成class文件后,也会存在一个默认的无参构造器 //显示的定义构造器 //1.无参构造器: public Person() { this.name = "jhz"; } //2.有参构造器:一旦定义了有参构造器,无参构造器就必须显示定义! public Person(String name) { this.name = name; } } /* public static void main(String[] args) { //使用new关键字实例化了一个对象 Person person = new Person("judy"); System.out.println(person.name); } 总结: 1.构造器: (1)与类名相同 (2)没有返回值 2.作用: (1)new本质在调用构造器 (2)用于初始化对象的值 3.注意点: (1)定义有参构造器之后,如果想使用无参构造器,必须显式定义一个无参构造器! (2)IDEA快捷键:Alt+(Fn)+Insert,选择"Constructor" */
构造器必须掌握!
-
-
创建对象内存分析:
![image-20251213163937875]()
- 栈:方法;引用变量名(会存放这个引用在堆里面的具体地址,对象是通过引用来操作的);存放基本类型的变量(会包含这个基本类型的具体数值)
- 堆:存放具体new创建出来的对象(和数组),可以被所有的线程共享
- 方法区:包含所有的class和static变量,可以被所有的线程共享
Java的三大特征
(一)封装:
-
该露的露,该藏的藏
-
程序设计追求”高内聚,低耦合“
- 高内聚:类的内部数据操作细节自己完成
- 低耦合:仅暴露少量的方法给外部使用
-
封装就是数据的隐藏:
通常,应该禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,这称为信息隐藏
-
总结:属性私有,get/set
-
Demo:
package com.oop.demo04; //类 public class Student { //private关键字:私有 private String name; //名字 private int age; //年龄 private int id; //学号 private char sex; //性别 //封装大都是对于属性而言,方法一般不需要封装 //学习(),睡觉() //提供一些可以操作这些属性的方法!(public的get/set方法) //get获得这个数据 public String getName() { return this.name; //this关键字是可选的(当前没有与成员变量同名的,局部变量或参数) } //set给这个数据设置值 public void setName(String name) { this.name = name; } //Alt+(Fn)+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; } //set中添加安全性判断,可以提高程序的安全性 public void setAge(int age) { if (age < 0 || age > 100) { System.out.println("年龄不合法!"); }else{ this.age = age; } } }package com.oop.demo04; /* 封装的作用: 1.提高程序的安全性(set中添加安全性判断),保护数据 2.隐藏代码的实现细节 3.统一接口 4.增加系统的可维护性 */ public class Application { public static void main(String[] args) { Student student = new Student(); //student.name不能得到属性值 String name = student.getName(); System.out.println(name); //null student.setName("judy"); System.out.println(student.getName()); //judy System.out.println(name); //null student.setAge(18); //如果设置的年龄不合法,则会输出“年龄不合法” System.out.println(student.getAge()); } }
(二)继承
-
继承的本质是对某一批类的抽象
-
extends的意思是“扩展”,子类是父类的扩展
-
Java中类只有单继承,没有多继承!
-
继承是类和类之间的一种关系。
- 除此之外,类和类之间的关系还有依赖、组合、聚合等
- 继承关系的两个类,一个是父类(基类),一个是子类(派生类)。
- 子类和父类之间,从意义上讲应该具有"is a"的关系
-
Demo:
package com.oop.demo05; //在Java中,所有的类,都默认直接或间接继承Object类 //人:父类 public class Person /*extands Object*/{ //关键字优先级:public, protected, default, private //一般父类的方法是public的(子类可继承),属性是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 com.oop.demo05; //Teacher is a Person: 派生类/子类 public class Teacher extends Person { }package com.oop.demo05; //Student is a Person: 派生类/子类 //子类继承了父类,就会拥有父类的全部public方法!(属性一般是private) public class Student extends Person { } -
Ctrl+H:可以查看与当前类相关的的层级结构
![image-20251213200647950]()
-
super关键字注意点:
- 通过super()调用父类的构造方法,必须写在构造方法的第一行
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法(因为这两者都要求写在第一行)
-
方法重写:(为什么需要重写:父类的功能,子类不一定需要)
需要有继承关系,子类重写父类的方法。重写都是方法的重写,和属性无关!
-
方法名必须相同
-
参数列表必须相同
-
方法体不同
-
修饰符,子类重写后的方法范围可以比父类扩大但不能缩小:puclic > protected > default > private
-
抛出的异常,范围可以缩小但不能扩大:Exception > ClassNotFoundException
-
Alt+Fn+Insert,选择override
-
Demo:
package com.oop; import com.oop.demo05.A; import com.oop.demo05.B; public class Application { public static void main(String[] args) { //静态方法与非静态方法的区别很大! //1.静态方法:方法的调用只与定义的数据类型(左边)有关,不算方法重写! A a = new A(); a.staTest(); //调用的A类的静态方法,A=>staTest() //父类(B)的引用b指向了子类(A) B b = new A(); b.staTest(); //调用的B类的静态方法,B=>staTest() //2.非静态方法:重写 a.test(); //A=>test() b.test(); //A=>test() } }package com.oop.demo05; public class A extends B { public static void staTest() { System.out.println("A=>staTest()"); } //Override重写 @Override //注解:有功能的注释! public void test() { System.out.println("A=>test()"); } }package com.oop.demo05; public class B { public static void staTest() { System.out.println("B=>staTest()"); } public void test() { System.out.println("B=>test()"); } }
-
(三)多态
-
同一个对象,在不同时刻表现出来的不同形态(即同一方法可以根据发送对象的不同而采用多种不同的行为方式)
Cat cat = new Cat(); Animal animal= new Cat(); -
一个对象的实际类型是确定的,但指向对象的引用的类型可以有多个(父类)
-
多态存在的条件:
- 有继承关系
- 子类重写父类的方法
- 父类引用指向子类对象:Father f1=new Son();
-
注意:多态是方法的多态,属性没有多态性!(animal的成员变量只有父类的属性)
-
Demo:
package com.oop; import com.oop.demo06.Student; import com.oop.demo06.Person; public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的! //new Student() //new Person() //可以指向的引用类型就不确定了:父类的引用可以指向子类 Student s1 = new Student(); Person s2 = new Student(); Object s3 = new Student(); s1.run(); //子类重写了父类的方法,则会执行子类的方法 s2.run(); //对象能执行哪些方法,主要看对象定义的类型(左边)! //子类能调用自己的、或继承自父类的方法;父类的引用可以指向子类的实例,但不能调用子类独有的方法 s1.eat(); ((Student)s2).eat(); //s2.eat();不能执行,因为Person类里没有eat()方法 } }package com.oop.demo06; public class Person { public void run(){ System.out.println("run"); } }package com.oop.demo06; public class Student extends Person { @Override public void run() { System.out.println("student run"); } public void eat() { System.out.println("student eat"); } } -
instanceof:1.判断两个类之间是否存在父子关系;2.准备进行引用类型转换
-
Demo:
package com.oop; import com.oop.demo06.Student; import com.oop.demo06.Person; import com.oop.demo06.Teacher; public class Application { public static void main(String[] args) { //Object > Person > Student //Object > Person > Teacher //Object > String //System.out.println(X instanceof Y); //能不能编译通过,取决于X与Y是否存在线性的父子关系 Object object = new Student(); System.out.println(object instanceof Student); //true System.out.println(object instanceof Person); //true System.out.println(object instanceof Object); //true System.out.println(object instanceof Teacher); //false System.out.println(object instanceof String); //false System.out.println("==================================="); Person person = new Student(); System.out.println(person instanceof Student); //true System.out.println(person instanceof Person); //true System.out.println(person instanceof Object); //true System.out.println(person instanceof Teacher); //false //System.out.println(person instanceof String); //编译报错!Person类和String类是同级的,根本没关系 System.out.println("==================================="); Student student = new Student(); System.out.println(student instanceof Student); //true System.out.println(student instanceof Person); //true System.out.println(student instanceof Object); //true //System.out.println(student instanceof Teacher); //编译报错!Student类和Teacher类是同级的,根本没关系 //System.out.println(student instanceof String); //编译报错!Student类和String类根本没关系 //引用类型之间的转换:父>子 //1.低 → 高,自动转换(子类转换为父类,可能丢失自己本来的一些方法!) Person p = new Student(); //p.go(); 无法调用Student类的go方法 //2.高→ 低,需要强制转换成子类 Student p1 = (Student) p; p1.go(); } }package com.oop.demo06; public class Person { public void run(){ System.out.println("run"); } }package com.oop.demo06; public class Student extends Person { public void go(){ System.out.println("go"); } }package com.oop.demo06; public class Teacher extends Person { }
-
-
补充知识:
-
static关键字详解
- 静态变量/非静态变量
- 静态方法/非静态方法
package com.oop.demo07; //static public class Student { private static int age; //静态变量/类变量(被类中的实例共享,建议使用“类名.变量名”访问) private double score; //非静态变量 public void run(){ System.out.println("run"); go(); //在同一个类里面,非静态方法可以直接调用静态方法 } public static void go(){ System.out.println("go"); } public static void main(String[] args) { Student s = new Student(); System.out.println(Student.age); //System.out.println(Student.score); 非静态变量不能通过类名.访问 System.out.println(s.age); System.out.println(s.score); // run();不能直接运行,必须通过new出来的对象.访问 new Student().run(); go(); //在同一个类里面,静态方法可以直接调用静态方法,但是不能直接调用非静态方法(需创建对象.) } }
-

-
代码块:
- 匿名代码块
- 静态代码块
package com.oop.demo07; public class Person { //2:赋初始值 { //代码块(匿名代码块) System.out.println("匿名代码块"); } //1:第一个执行(和类一起加载)只执行一次 static{ //静态代码块 System.out.println("静态代码块"); } //3. public Person() { //构造器 System.out.println("构造方法"); } public static void main(String[] args) { Person p1 = new Person(); System.out.println("==============="); //每创建一个对象,就会先走匿名代码块,在执行构造函数 Person p2 = new Person(); } /* output: 静态代码块 匿名代码块 构造方法 =============== 匿名代码块 构造方法 */ } -
final修饰符:final修饰的类不可以被继承,没有子类!
-
静态导入包:
package com.oop.demo07; //静态导入包: import static java.lang.Math.random; import static java.lang.Math.PI; public class Test { public static void main(String[] args) { //System.out.println(Math.random()); //静态导入包之后可以直接调用random() System.out.println(random()); System.out.println(PI); } }
抽象类和接口
(一)抽象类
-
abstract修饰符可以修饰方法也可以修饰类。(抽象方法/抽象类)
-
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类!
- 抽象类,不能使用new关键字创建对象,它是用来让子类继承的
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的
-
子类继承抽象类,那么就必须实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
-
Demo: 抽象类是一种”约束“、”规范“
package com.oop.demo08; //抽象类:extends类都是单继承(接口可以多继承) public abstract class Action { //抽象方法:只有方法名,没有方法的实现 public abstract void doSomething(); }package com.oop.demo08; //抽象类的所有方法,继承它的子类都必须实现(除非这个子类本身也是abstract抽象类) public class A extends Action{ @Override public void doSomething() { } } -
思考题:
- 抽象类存在构造器;
- 存在读意义:提高代码开发效率和可扩展性
(二)接口(interface)
-
对比:
- 普通类:只有具体的实现
- 抽象类:具体的实现和规范(抽象方法)都有!
- 接口:只有规范!(约束和实现分离)
-
接口就是规范,定义的是一组规则
-
接口的本质是契约
-
Demo:
package com.oop.demo09; //interface关键字定义的是接口,接口都需要有实现类 public interface UserService { //接口中的属性都是常量(public static final),但一般不在接口中定义常量! //public static final int AGE=99; int AGE=99; //接口中的所有定义的方法,其实都是public abstract的 //public abstract void run(); void add(String name); void delete(String name); void update(String name); void querye(String name); }package com.oop.demo09; public interface TimeService { void timmer(); }package com.oop.demo09; //接口的实现类名字一般都以"Impl"结尾 //抽象类的继承:extends只有单继承 //类可以通过"implements接口"实现接口;实现了接口的类,就必须重写接口中的定义的方法! //多继承:通过接口间接实现多继承 public class UserServiceImpl implements UserService,TimeService { @Override public void add(String name) { } @Override public void update(String name) { } @Override public void delete(String name) { } @Override public void querye(String name) { } @Override public void timmer() { } } -
总结:
-
接口就是约束(定义了一些方法,让不同的人实现)
-
接口中的所有定义的方法,都是public abstract的
-
接口中的属性都是常量(public static final),但一般不在接口中定义常量!
-
接口中没有构造器,接口不能被实例化
-
通过implements关键字可以实现多个接口(extends则只能单继承类)
-
必须要重写接口中的方法
-
内部类
-
内部类就是在一个类的内部再定义一个类(比如,在A类中定义一个B类,则B类就是A的内部类,而A类是B类的外部类)
-
分类:
-
成员内部类
package com.oop.demo10; public class Outer { private int id=10; private void out(){ System.out.println("这是外部类的方法"); } public class Inner { public void in(){ System.out.println("这是内部类的方法"); } //内部类可以获取外部类的私有属性和私有方法!(public的就更能获取了) public void getid(){ System.out.println(id); out(); } } }package com.oop; import com.oop.demo10.Outer; public class Application { public static void main(String[] args) { Outer outer= new Outer(); //通过外部类来实例化内部类 Outer.Inner inner=outer.new Inner(); inner.in(); inner.getid(); } } -
静态内部类:static的内部类不能访问外部类中非static的属性
-
局部内部类:写在方法里面的类
![image-20251215204954725]()
-
匿名内部类:没有类名,只使用一次,在定义的同时被实例化
通常用于需要临时:1.实现某个接口-最常用;2.继承普通类并重写方法;3.继承抽象类并实现抽象方法
-
-
一个 Java 源文件中可以有多个类(class),但最多只能有一个 public类,且这个public class的名称必须与源文件名相同。






浙公网安备 33010602011771号