前言
Java的面向对象(oop)学习笔记
类
- 一个
.java文件可以定义多个类,但只能有一个由public修饰的类,文件名需要与public修饰的类的类名保持一致
- 类名首字母大写
类名.java1 2 3 4 5 6 7 8 9 10 11
| public class 类名 { ... }
class 类名1 { ... }
class 类名2 { ... }
|
对象
属性
方法
1 2 3 4 5 6 7 8
| class 类名 { 返回值类型 方法名(参数列表) { ... return 返回值; } }
|
方法的参数列表
1 2 3 4 5
| class 类名 { void 方法名(数据类型 参数名) { ... } }
|
可变长参数
- 可变长参数得到的是一个数组
- 可变长参数必须在形参列表最后定义
1 2 3 4 5
| class 类名 { void 方法名(数据类型 参数名1, 数据类型... 参数名2) { 数据类型[] 变量名 = 参数名2; } }
|
方法的重载
- 同一个类中定义多个同名方法,方法名相同,参数列表不同
1 2 3 4 5 6 7 8
| class 类名 { void 方法名(数据类型 参数名1) { ... } void 方法名(数据类型 参数名1, 数据类型 参数名2) { ... } }
|
方法的返回值
1 2 3 4 5 6 7 8
| class 类名 { 数据类型 方法名() { ... return 返回值; } }
|
构造方法
- 构造方法名与类名同名
- 构造方法没有返回值类型,也无需使用
void关键字
- 没有定义构造方法时,类中默认包含一个无参构造方法
- 通过
new关键字创建对象时,构造方法会被执行
1 2 3 4 5
| class 类名 { 类名(参数列表) { ... } }
|
this
- 通过
this访问当前实例
this只能在方法中使用
- 方法中访问实例属性和实例方法时可以省略
this.
访问实例属性
1 2 3 4 5 6 7 8
| class 类名 { 数据类型 属性名; void 方法名() { System.out.println(this.属性名); System.out.println(属性名); } }
|
调用实例方法
1 2 3 4 5 6 7 8 9 10
| class 类名 { void 方法名() { ... }
void 方法名2() { this.方法名(); 方法名(); } }
|
调用构造方法
- 通过
this()调用当前类的其他构造方法
this()只能用在构造方法中
this()必须位于构造方法的第一行
1 2 3 4 5 6 7 8 9
| class 类名() { 类名() { ... } 类名(int a) { this(); } }
|
final
修饰变量
修饰类
修饰属性
修饰方法
static
静态属性
1 2 3 4 5 6 7 8 9
| class 类名 { static 数据类型 属性名; }
class Main { public static void main(String[] args) { System.out.println(类名.属性名); } }
|
静态方法
1 2 3 4 5 6 7 8 9 10 11
| class 类名 { static void 方法名() { ... } }
class Main { public static void main(String[] args) { 类名.方法名(); } }
|
静态代码块
1 2 3 4 5
| class 类名 { static { ... } }
|
类创建对象时的执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Cls { Cls() { System.out.println("构造方法"); }
static int a = initA(); static int initA() { System.out.println("静态属性初始化"); return 1; } int b = initB(); int initB() { System.out.println("实例属性初始化"); return 1; }
{ System.out.println("普通代码块"); } static { System.out.println("静态代码块"); } }
class Main { public static void main(String[] args) { Cls cls = new Cls(); } }
|
1 2 3 4 5
| 静态属性初始化 静态代码块 成员属性初始化 普通代码块 构造方法
|
继承
- 通过
extends继承父类
- 子类只能继承一个父类
- 子类继承父类后,子类实例可以访问父类属性和方法
1 2 3 4 5 6 7
| class Father { ... }
class Son extends Father { ... }
|
方法的重写
- 子类重写父类同名方法
@Override注解用于标注这是重写的方法
1 2 3 4 5 6 7 8 9 10 11 12
| class Father { public void 父类方法名() { ... } }
class Son extends Father { @Override public void 父类方法名() { ... } }
|
super
- 通过
super访问父类实例
super只能在方法中使用
访问父类实例属性
1 2 3 4 5 6 7 8 9
| class Father { 数据类型 属性名; }
class Son extends Father { public void 方法名() { System.out.println(super.属性名); } }
|
访问父类实例方法
1 2 3 4 5 6 7 8 9 10 11
| class Father { public void 父类方法名() { ... } }
class Son extends Father { public void 子类方法名() { super.父类方法名(); } }
|
访问父类构造方法
- 通过
super()调用父类构造方法
super()只能用在构造方法中
super()必须位于子类构造方法的第一行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Father { public Father() { ... } }
class Son extends Father { public Son() { super(); ... } }
|
抽象类和抽象方法
定义抽象类
1 2 3
| abstract class 抽象类名 { ... }
|
抽象类中定义抽象方法
- 通过
abstract关键字修饰的方法是抽象方法,抽象方法不需要定义方法体
- 抽象类中定义的方法可以是抽象的也可以不是抽象的
1 2 3 4 5 6 7
| abstract class 抽象类名 { abstract void 抽象方法名(); void 普通方法名() {} }
|
子类继承抽象类
- 子类通过
extends继承抽象类
- 子类只能继承一个父类
- 子类继承抽象类时必须重写抽象类中的所有抽象方法
1 2 3 4 5 6
| class 子类 extends 抽象类名 { @Override void 抽象方法名() { ... } }
|
- 如果不重写接口定义的所有抽象方法,则子类一定也是抽象类
1 2 3 4
| abstract class 子类 extends 抽象类名 { @Override abstract void 抽象方法名(); }
|
接口
定义接口
接口中定义抽象方法
1 2 3
| interface 接口名 { public abstract void 抽象方法名(); }
|
- 接口中定义抽象方法时可以省略
public、abstract关键字
1 2 3
| interface 接口名 { void 抽象方法名(); }
|
接口中抽象方法的默认实现
1 2 3 4 5
| interface 接口名 { default void 抽象方法名() { ... } }
|
接口中定义常量属性
1 2 3
| interface 接口名 { public static final 数据类型 属性名 = 值; }
|
- 接口中定义常量属性时可以省略
public、static、final关键字
1 2 3
| interface 接口名 { 数据类型 属性名 = 值; }
|
接口中定义静态方法
1 2 3 4 5
| interface 接口名 { public static void 静态方法名() { ... } }
|
1 2 3 4 5
| interface 接口名 { static void 静态方法名() { ... } }
|
子类实现接口
- 子类通过
implements实现接口
- 子类可以实现多个接口,多个接口名之间用
,分隔
- 子类实现接口时必须重写所有接口定义的所有抽象方法
1 2 3 4 5 6 7 8 9 10 11 12
| interface 接口名1 { void 抽象方法名(); }
interface 接口名2 {}
class 类名 implements 接口名1, 接口名2 { @Override public void 抽象方法名() { ... } }
|
- 如果不重写接口定义的所有抽象方法,则子类一定是抽象类
1 2 3 4 5 6 7 8 9 10
| interface 接口名1 { void 抽象方法名(); }
interface 接口名2 {}
abstract class 类名 implements 接口名1, 接口名2 { @Override public abstract void 抽象方法名(); }
|
多态
父类引用指向子类对象
父类引用转换为子类对象
1 2 3 4
| 父类名 对象名 = new 子类名(); if (对象名 instanceof 子类名) { 子类名 子对象名 = (子类名) 对象名; }
|
权限修饰符
|关键字|权限|当前类|当前类及子类|当前包|当前项目|
|—|—|—|—|—|
|public|公共权限|✓|✓|✓|✓|
|protected|保护权限|✓|✓|✓|×|
|无修饰符||✓|✓|×|×|
|private|私有权限|✓|×|×|×|
1 2 3 4 5 6 7 8 9 10 11
| class 类名 { public void 方法名() {} protected void 方法名() {} void 方法名() {} private void 方法名() {} }
|
包管理
package
1 2 3 4 5
| package 包名;
class 类名 { ... }
|
import
引入指定包中的指定类
引入指定包中的所有类
直接引入静态类中的属性或方法
1 2
| import static 包名.类名.属性名; import static 包名.类名.方法名;
|
直接通过类的全局限定名访问类
1
| 包名.类名 对象名 = new 包名.类名();
|
成员内部类
定义内部类
1 2 3 4 5
| class Outer { class Inner { ... } }
|
创建对象
在外部类中创建内部类对象
1 2 3 4 5 6 7 8 9 10 11 12
| class Outer { class Inner { int field; void method() {} } void fn() { Inner inner = new Inner(); System.out.println(inner.field); inner.method(); } }
|
在其他类中创建内部类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Outer { class Inner { int field; void method() {} } }
public class Cls { public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); System.out.println(inner.field); inner.method(); } }
|
内部类访问外部类的属性和方法
1 2 3 4 5 6 7 8 9 10 11 12
| class Outer { int field; void method() {} class Inner { void fn() { System.out.println(field); method(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Outer { int field; void method() {} class Inner {
int field; void method() {} void fn() { System.out.println(Outer.field); Outer.method(); System.out.println(field); method(); } } }
|
- 外部类属性名、内部类属性名、方法内变量名重名时,需要显式指定访问的属性或变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Outer {
int field; class Inner {
int field; void fn(int field) { System.out.println(Outer.this.field); System.out.println(this.field); System.out.println(field); } } }
|
静态内部类
定义内部类
1 2 3 4 5
| class Outer { static class Inner { ... } }
|
定义内部接口
1 2 3 4 5
| class Outer { static interface Inner { ... } }
|
1 2 3 4 5
| class Outer { interface Inner { ... } }
|
创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Outer { static class Inner { int field; void method() {} } }
public class Cls { public static void main(String[] args) { Outer.Inner inner = new Outer.Inner(); System.out.println(inner.field); inner.method(); } }
|
局部内部类
定义内部类
1 2 3 4 5 6 7
| class Outer { void fn() { class Inner { ... } } }
|
创建对象
1 2 3 4 5 6 7 8 9 10 11 12
| class Outer { void fn() { class Inner { int field; void method() {} } Inner inner = new Inner(); System.out.println(inner.field); inner.method(); } }
|
匿名内部类
通过匿名内部类为抽象类或接口创建对象
- 创建对象时,通过匿名内部类,直接重写接口或抽象类的抽象方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| abstract class Cls { void method(); }
public class Main { public static void main(String[] args) { Cls cls = new Cls() { @Override public void method() { ... } }; cls.method(); } }
|
Lambda表达式
- 有且只有一个抽象方法的接口使用匿名内部类时,可以将匿名内部类简写为Lambda表达式
1 2 3 4 5 6 7 8 9 10 11 12
| interface Cls { int method(int arg); }
public class Main { public static void main(String[] args) { Cls cls = (int arg) -> { return 0; }; cls.method(); } }
|
- 如果方法体只有一行,那么可以省略
{}和return关键字
1 2 3 4 5 6 7 8 9 10
| interface Cls { int method(int arg); }
public class Main { public static void main(String[] args) { Cls cls = (int arg) -> 0; cls.method(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| interface Cls { int method(int arg); }
public class Main { public static void main(String[] args) { Cls cls = arg -> { return 0; }; cls.method(); } }
|
方法引用
- 有且只有一个抽象方法的接口使用匿名内部类时,如果接口的这个方法的形参列表与返回值类型与其他方法的形参列表与返回值类型都相同,可以使用
::作为方法引用
实例方法引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Cls { int methodFromCls(int num) { return num; } }
interface Inf { int methodFromInf(int num); }
public class Main { public static void main(String[] args) { Cls cls = new Cls(); Inf inf = cls::methodFromCls; inf.methodFromInf(0); } }
|
静态方法引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Cls { static int methodFromCls(int num) { return num; } }
interface Inf { int methodFromInf(int num); }
public class Main { public static void main(String[] args) { Inf inf = Cls::methodFromCls; inf.methodFromInf(0); } }
|
- 有且只有一个抽象方法的接口使用匿名内部类时,如果接口的这个方法的形参为指定类型,返回值类型与指定类型的指定方法的返回值类型相同,也可以使用
::作为方法引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Cls { int methodFromCls() { return 0; } }
interface Inf { int methodFromInf(Cls cls); }
public class Main { public static void main(String[] args) { Inf inf = Cls::methodFromCls; inf.methodFromInf(new Cls()); } }
|
构造方法引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Cls { Cls(int num) { ... } }
interface Inf { Cls methodFromInf(int num); }
public class Main { public static void main(String[] args) { Inf inf = Cls::new; inf.methodFromInf(0); } }
|
通过匿名内部类创建对象并作为方法形参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| abstract class Cls { int method(int arg); }
public class Main { static void fn(Cls cls) { System.out.println(cls); } public static void main(String[] args) { fn(new Cls() { @Override public void method() { ... } }); } }
|
完成
参考文献
哔哩哔哩——青空の霞光