面向对象 (Java)
什么是 OOP
面向对象编程(Object-Orien Programming,OOP)
- 面向过程:编写对数据执行的过程或方法
- 面向对象:创建同时包含数据和方法的对象
类和对象:
- 类是对象的模板,而对象是类的实例
- 创建各个对象时,它们会从类中继承所有变量和方法
类和对象
创建:
创建类:
class
(大写开头,java 文件的名称应与类名匹配)1
2
3
4class Person {
public String name;
public int age;
}创建实例:
new
1
Person ming = new Person();
**属性:**访问、修改:.
方法
定义
1 | 修饰符 方法返回类型 方法名(方法参数列表) { |
修饰符:
private
:只能在类内部调用static
:静态方法,属于类本身,不需要创建对象也能调用public
:任何类可访问
**this:**指向当前实例
可变参数:类型...
1 | class Group { |
按值传递 vs 引用传递:
类型 | 传递 | 更改后输出是否变化 |
---|---|---|
基本数据类型 | 按值传递 | 不变 |
引用类型(数组、对象) | 引用传递(可在原有地址改变) | 变 |
字符串、不可变类型 | 引用传递(修改会创建新对象) | 不变 |
构造方法
要求:
- 方法的名称是类名
- 没有返回值(没有
void
) - 调用:
new
1 | // 构造方法 |
重载
重载 overload:
- 方法名相同
- 参数列表不同:数量、类型、顺序
- 返回值可不同
1 | class Hello { |
方法链
要求:
- 前一个方法返回类本身
this
- 或者是构造函数
修饰符
- 访问控制修饰符 - 控制访问级别
- 非访问控制修饰符 - 不控制访问级别,但提供其他功能
访问修饰符
对于类:
修饰符 作用 public
所有类都能访问 默认不写 同包内可访问 对于属性、方法和构造函数:、
修饰符 作用 public
所有类都能访问 private
仅限当前类可访问 默认不写 同包内可访问 protected
同包 或 子类可访问
非访问修饰符
对于类:
修饰符 作用 final
表示类不可继承 abstract
表示类是抽象类,不能实例化 对于属性和方法:
修饰符 作用 final
属性和方法不能被重写、修改 static
属性方法属于类,而不是实例 abstract
只能在抽象类的抽象方法中使用,方法没有主体 transient
属性和方法不会被序列化 synchronized
方法一次只能由一个线程访问 volatile
属性的值不在线程本地缓存,而是始终从“主内存”读取
包
导入类:import java.util.Scanner;
导入整个包:import java.util.*;
(不包括子包的 class
)
**命名:**倒置域名
作用域
**类作用域:**在整个类中可访问
**方法作用域:**只能在该方法中访问
**块作用域:**变量只能在块内访问
**循环作用域:**变量只能在循环体内访问
**包作用域:**同包内可访问(没用任何修饰符 public
、private
、protected
)
封装
封装:确保对用户敏感的数据进行隐藏
private
:声明变量/属性(只能在同一个类中访问,外部类无权访问)Get
、Set
方法:访问、更新private
变量
Get Set
get
方法返回变量值,set
方法设置值
两者的语法是它们都以 get
或 set
开头,后跟变量的名称,第一个字母为大写:
1 | public class Person { |
意义
- 更好地控制类属性和方法
- 类属性可以是只读的(如果只使用
get
方法),也可以是只写的(如果只使用set
方法) - 灵活:程序员可以更改代码的一部分,而不会影响其他部分
- 提高数据安全性
继承
extends:
- 子类:从另一个类继承的类
- 父类:被继承的类
1 | class Vehicle { |
修饰符:
protected
:子类无法访问父类的字段、方法protected
:子类可访问final
:其他类无法继承
super:
子类引用父类的字段
父类没有默认构造方法,子类必须显式调用
super
并给出参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Person {
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
protected int score;
public Student(String name, int age, int score) {
super(name, age); // 调用父类的构造方法Person(String, int)
this.score = score;
}
}
向上转型:Person p = new Student();
p
是Person
类型的引用变量,指向Student
对象(实例)- 编译时是
Person
,运行时是Student
向下转型:
1 | Person p1 = new Student(); // upcasting, ok |
Person
类型p1
实际指向Student
实例:成功Person
类型变量p2
实际指向Person
实例:失败,子类功能比父类多
**instanceof:**判断变量指向的实例是否是指定类型,或者这个类型的子类,若是可直接转型
1 | public class Main { |
多态
重写 @override:
- 方法名相同
- 参数列表相同
- 返回类型相同
**多态:**真正执行的方法取决于运行时期实际类型的方法
重写 vs 重载:
重写:
1 | public class Processor { |
重载:
1 | public class Processor { |
抽象
abstract:
- **抽象类:**不能创建对象,只能继承(可同时拥有抽象,普通方法、字段)
- **抽象方法:**只能在抽象类中使用,子类必须全部重写
1 | // abstract class |
接口
**接口:**没有字段,所有方法都是抽象方法的抽象类(默认 public abstract
可不写)
具体实例实现接口:implements
1 | class Student implements Person { |
接口继承:
1 | interface Hello { |
**default 方法:**具体实现类可以不用重写 default
方法
内部类
内部类
要实例化内部类,需要先创建外部类:
1 | public class Main { |
内部类可以访问外部类的 private
字段
匿名类
1 | public class Main { |
静态内部类
static
:可以直接创建
1 | public class Main { |
核心类
字符串
特点:
- 引用类型,本身是
class
,但可以"..."
定义 - 不可变:更改是在新空间创建新字符串
比较:.equals()
包含:.contains()
去除首尾空白字符:
.trim()
(\t
,\r
,\n
).strip()
是否为空:isEmpty()
替换:s.replace('l', 'w');
分割:split()
拼接:join("...", arr);
格式化:
formatted()
format()
类型转换:
- 转换为字符串:
String.valueOf()
- 转换为其他类型:
Integer.parseInt
,Boolean.parseBoolean
- 转换为
char[]
:.toCharArray()
StringBuilder
创建:StringBuilder sb = new StringBuilder();
添加:.append()
转换为字符串:.toString()
插入:.insert(index, "...")
可进行链式操作
StringJoiner
拼接: var sj = new StringJoiner(", ", "Hello ", "!");
(中间,头,尾)
包装类
基本类型 -> 引用类型
不变类
基本类型 | 引用类型 |
---|---|
boolean | java.lang.Boolean |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
比较:.equals()
JavaBean
**JavaBean:**如果读写方法符合以下命名规范,那么这种 class
被称为 JavaBean
(封装)
1 | // 读方法: |
枚举 JavaBean 的属性:
1 | import java.beans.*; |
枚举类
enum:enum
类型就是 class
(引用类型)
- 继承自
java.lang.Enum
,且无法被继承 - 只能定义
enum
的实例,无法通过new
创建 - 定义的每个实例都是引用类型的唯一实例
- 可用于
switch
语句
创建:
1 | public enum Color { |
编译出的 class
文件:
1 | public final class Color extends Enum { // 继承自Enum,标记为final class |
比较:==
(不像其他引用类型只能用 equals()
)
常量名:String s = Weekday.SUN.name(); // "SUN"
常量顺序:int n = Weekday.MON.ordinal(); // 1
(从0开始)
添加字段:
1 | enum Weekday { |
记录类
record:
- 用
final
修饰class以及每个字段(实现不变类) - 自动创建构造方法,重写
toString()
、equals()
、hashCode()
- 不能直接从
Record
派生,只能通过关键词由编译器实现继承
1 | record Point(int x, int y) {...} |
相当于:
1 | final class Point extends Record { |
BigInteger
创建:BigInteger bi = new BigInteger("1234567890");
**运算:**只能用实例
1 | BigInteger i1 = new BigInteger("1234567890"); |
转换为基本类型:
- 转换为
byte
:byteValue()
- 转换为
short
:shortValue()
- 转换为
int
:intValue()
- 转换为
long
:longValue()
- 转换为
float
:floatValue()
- 转换为
double
:doubleValue()
BigDecimal
创建:BigDecimal bd = new BigDecimal("123.4567");
小数位数:.scale()
去掉末尾0:stripTrailingZeros()
比较:
compareTo()
:比较大小equals()
:比较大小和scale()