Java基础笔记9(类与对象)
Java基础笔记9(类与对象)
面向对象
- 面向对象编程(Object-Oriented Programing,OOP)
- 面向对象编程的本质:以类的方式组织代码,以对象的形式组织(封装)数据
- 三大特性
- 封装
- 继承
- 多态
- 对象是具体的事物,类是对对象的抽象
- 从代码运行的角度,先有类再有对象,类是对象的模板
类
- 属性:
- 又叫字段(Field)或成员变量
- 默认初始化
- 数字:0、0.0
- char:u0000
- boolean:false
- 引用:null
- 修饰符 属性类型 属性名 = 属性值
- 方法
- 修饰符 返回类型 方法名(){ 方法体 }
1 | public class 类名 { |
对象
- 对象的创建和使用
- 使用new关键字创建对象 Student stu = new Student();
- 对象的属性stu.name; 前提属性name不是私有的
- 对象的方法stu.getName();
1 | //类实例化后会返回一个自己的对象 |
构造器
- 构造器名和类名相同,无返回值
- 使用new关键字,本质是在调用构造器
- 构造器用来初始化值
- 一个类即使什么都不写,也会有一个默认构造方法(无参构造)
- 一但定义了有参构造,无参构造就必须显式定义
1 | public class Student { |
1 | Student zhangsan = new Student("张三"); |
封装
高内聚、低耦合
- 高内聚:类内部的数据操作细节自己完成
- 低耦合:暴露少量的方法供外部使用
数据隐藏
通常禁止直接访问一个对象中数据的实际表示,而应通过操作接口来进行访问
get\set
1
2
3
4
5
6
7
8
9
10public class Student {
private String name;
public String getName() { return name; }
public void setName() {
this.name = name;
}
}
继承
依赖、关联、组合、聚合
继承是类与类之间的一种关系,除此之外类与类之间的关系还有依赖、关联、组合、聚合等
依赖:
- 类A中的方法使用到了另一个类B,B类的变化会影响到A,具有偶然性、临时性。
1
2
3
4
5
6
7
8
9
10
11
12//一般依赖关系在Java中体现为局域变量、方法的形参,或者对静态方法的调用。
public class Money {
public void count(){
System.out.println("count money");
}
}
public class Person {
public void countMoney (Money money){//money作为Person类方法的参数。Person类依赖Money类
money.count();
}
}关联:
- 体现的是两个类、或者类与接口之间语义级别的一种强依赖关系。
- 这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的
- 一般是长期性的,而且双方的关系一般是平等的,关联可以是单向、双向的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//关联关系一般使用成员变量来实现。
public class Money {
public void count(){
System.out.println("count money");
}
}
public class Person {
private Money money;
public Person(Money money){
this.money = money;
}
public void countMoney (){
money.count();
}
}聚合:
- 聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系
- 在代码层面,聚合和关联关系是一致的,只能从语义级别来区分。普通的关联关系中,a类和b类没有必然的联系,而聚合中,需要b类是a类的一部分,是一种has a的关系,即 a has a b; 比如班级里有学生。
- has a不是 must has a,a可以有b,也可以没有。a是整体,b是部分,整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。
1
2
3
4
5
6//不同于关联关系的平等地位,聚合关系中两个类的地位是不平等。
public class MyClass {
private List<Student> students; //一个家庭里有许多孩子
//...
}
组合:
- 组合也是关联关系的一种特例,他体现的是一种contains a的关系,这种关系比聚合更强,也称为强聚合。
- 组合同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束。
1
2
3
4
5
6
7//组合关系中,两个类关系也是不平等的。
public class Person {
private Arm arm;
private Leg leg;//一个人有手有脚,但人没了,手和脚也就没意义了
// ....
}
继承
继承的本质是对某一批类的抽象
继承关系的两个类
一个为子类(派生类)
一个为父类(基类)
子类继承父类,使用关键字extends来表示
子类 extends 父类
1
2
3public class Student extends Persion {
//...
}子类可以继承父类所有非私有属性和方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//父类
public class Father {
public String lastName = "李";
private String firstName = "四";
protected int money = 2333;
public void publicFun(){}
private void privateFun(){}
protected void protectedFun(){}
}
//子类
public class Son extends Father {}
//测试子类可以调用的父类中哪些属性和方法
public class Test {
public static void main(String[] args) {
Son son = new Son();
String lastName = son.lastName;
int money = son.money;
son.publicFun();
son.protectedFun();
}
}
Java中类只有单继承,没有多继承
- 一个子类只能直接继承一个父类,但可以间接继承多个父类
子类和父类之间,从意义上讲应该具有“is a”的关系
- Student is a Person
Object类
- 在Java中,所有的类都默认直接或间接继承Object
super
子类通过super来访问父类的方法和属性
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
31
32
33
34
35
36
37
38
39
40
41public class Father {
public String lastName = "李";
public String firstName = "老四";
public void test(){
System.out.println("父类方法");
System.out.println(firstName);
System.out.println(this.firstName);
}
}
public class Son extends Father {
public String firstName = "小四";
public void test(){
System.out.println("子类方法");
super.test();
System.out.println("父类方法结束");
System.out.println(firstName);
System.out.println(this.firstName);
System.out.println(super.firstName);
}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
/*
输出:
子类方法
父类方法
老四
老四
父类方法结束
小四
小四
老四
*/子类的构造器必须调用父类的构造器;
调用父类构造器必须是子类构造器第一行代码
子类构造器默认调用父类无参构造super();
方法重写
- 需要继承关系,子类重写父类方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符范围可以扩大不能缩小
- 抛出异常范围可以缩小但不可以扩大
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
27public class B {
public static void test(){
System.out.println("B=>test()");
}
}
public class A extends B {
public static void test(){
System.out.println("A=>test()");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.test();
//父类的引用指向子类
B b = new A();
b.test();
}
}
/*
输出:
A=>test()
B=>test()
*/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
31//方法去掉static后
public class B {
public void test(){
System.out.println("B=>test()");
}
}
public class A extends B {
public void test(){
System.out.println("A=>test()");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.test();
//父类的引用指向子类
B b = new A();
b.test();
}
}
/*
输出:
A=>test()
A=>test()
静态方法是类的方法,非静态方法是对象的方法
b是A new出来的对象,因此调用了A的方法
*/
多态
- 即同一方法可以根据发送对象的不同而采用多种不同行为方式
- 一个对象的实际类型是确定的,但可以指向的引用的类型有很多
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 多态是方法的多态,属性没有多态性
- instanceof
1 | public class Father { |
instanceof
instanceof 用来测试一个对象是否为一个类的实例
1 | boolean result = obj instanceof Class |
obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
几种情况
obj 必须为引用类型,不能是基本类型,否则编译不通过
1
2
3int i = 0;
System.out.println(i instanceof Integer);//编译不通过
System.out.println(i instanceof Object);//编译不通过如果 obj 为 null,那么将返回 false
1
System.out.println(null instanceof Object);//false
obj 可以为 class 类的实例对象
1
2Integer integer = new Integer(1);
System.out.println(integer instanceof Integer);//trueobj 可以为 class 类的直接或间接子类
1
2
3
4
5
6
7
8
9public class Father {}
public class Son extends Father {}
Father test1 = new Father();
Father test2 = new Son();
Son test3 = new Son();
System.out.println(test1 instanceof Son);//false
System.out.println(test2 instanceof Son);//true
System.out.println(test3 instanceof Son);//trueobj 可以为接口的实现类
1
2
3
4
5
6
7public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList arrayList = new ArrayList();
System.out.println(arrayList instanceof List);//true
List list = new ArrayList();
System.out.println(list instanceof ArrayList);//true
static
静态变量、静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class Test {
//static表示从属该类,跟类一起加载
private int id;
private static int sid;
public void fn(){}
public static void sfn(){}
public static void main(String[] args) {
int sid1 = sid;
int sid2 = Test.sid;
int id = new Test().id;
sfn();
Test.sfn();
new Test().fn();
}
}静态代码块、匿名代码块
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
30public class Test {
//匿名代码块
{
System.out.println("匿名代码块");
}
//静态代码块 静态代码块只执行一次
static {
System.out.println("静态代码块");
}
Test() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Test test1 = new Test();
System.out.println("=============");
Test test2 = new Test();
}
}
/*
输出:
静态代码块
匿名代码块
构造方法
=============
匿名代码块
构造方法
*/静态导入包
1
2
3
4
5
6
7
8
9
10
11
12
13
14//未导包前,调用Math.random()方法
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
}
}
//使用静态导入包后,调用Math.random()方法
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
System.out.println(random());
}
}
抽象类
- 抽象类不能new,只能靠子类去实现
- 抽象类中可以写普通方法
- 抽象方法必须写在抽象类中
- 抽象类也有构造器
1 | //abstract修饰抽象类 |
接口
- 普通类:具体实现
- 抽象类:具体实现和规范(抽象方法)
- 接口:规范
- 接口不能有构造方法,抽象类有构造方法
1 | //interface 定义的关键字,接口需要有实现类 |
内部类
成员内部类
静态内部类
局部内部类
匿名内部类
1 | public class Outer { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 PlanZ!