JavaSE

  1. 1. 面向对象(Object-Oriented Programming, OOP)
    1. 1.1. 方法的定义和调用
    2. 1.2. 构造器详解
    3. 1.3. 封装详解
    4. 1.4. 继承
      1. 1.4.1. 继承的特性
      2. 1.4.2. super与this关键字
      3. 1.4.3. final关键字
    5. 1.5. 重写(Override)与重载(Overload)
    6. 1.6. 多态
      1. 1.6.1. instanceof关键字
    7. 1.7. static关键字详解
      1. 1.7.1. static代码块
      2. 1.7.2. 静态导入包
    8. 1.8. 抽象类
    9. 1.9. 接口的定义与实现
    10. 1.10. 内部类
  2. 2. 参考

作为一款"工业级"编程语言,Java的重要性不言而喻

面向对象(Object-Oriented Programming, OOP)

面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据

方法的定义和调用

方法的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Demo01 类
public class Demo01 {
// main 方法
public static void main(String[] args) {

}
}
/*
修饰符 返回值类型 方法名(...) {
// 方法体
return 返回值
}
*/
public int max(int a, int b) {
return a > b ? a : b;
}

方法的调用:

调用其他类的方法,除非是static静态方法,不然必须实例化这个类(new)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo02 {

public static void main(String[] args) {
// 通过类名直接调用静态方法
int add = Demo02.add(1, 2);

// 非静态方法需要先实例化这个类new
// 对象类型 对象名 = 对象值;
Student student = new Student();
student.say();
}

public static int add(int a, int b) {
return a + b;
}
}
1
2
3
4
5
6
7
8
// 学生类
public class Student {

// 非静态方法
public void say() {
System.out.println("xxxx");
}
}

构造器详解

使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化,以及对类中构造器的调用

类中的构造器也被称为构造方法,创建对象时必须要调用。有以下特点:

  1. 必须和类的名字相同
  2. 没有返回类型,也不能写void

构造器的作用:

  1. 使用new关键字,本质是在调用构造器
  2. 用来初始化值

封装详解

程序设计要追求:高内聚,低耦合。高内聚:类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用

封装(数据的隐藏):通常应禁止直接访问一个对象中的数据的实际表示,而应通过操作接口来访问,这称为信息隐藏

属性私有,get/set

1
2
3
4
5
6
7
8
9
public class Demo03 {

public static void main(String[] args) {
Student s1 = new Student();

s1.setName("java");
System.out.println(s1.getName());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 学生类
public class Student {

// 属性私有
private String name;
private int id;
private char sex;

// 提供一些可以操作这个属性的方法
// 提供一些public的get,set方法

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}
}

有时set中会做一些不合法数据的处理。由此看出,封装可以

  1. 提高程序的安全性,保护数据
  2. 隐藏代码的实现细节
  3. 统一接口
  4. 系统可维护增加

继承

Java中类只有单继承,没有多继承!

1
2
3
4
5
6
7
8
9
10
11
public class Animal {

private String name;
private int id;

public Animal(String myName, String myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}
1
2
3
public class Penguin extends Animal { 

}

继承的特性

  1. 子类拥有父类非private的属性,方法
  2. 子类可以用有自己的属性和方法,即子类可以对父类进行扩展
  3. 子类可以用自己的方式实现父类的方法
  4. 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)

super与this关键字

  • super:可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
  • this:指向自己的引用
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
class Animal {
void eat() {
System.out.println("animal : eat");
}
}

class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}

void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}

public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat(); // 输出:animal : eat

Dog d = new Dog();
d.eatTest(); // 输出:dog : eat
// 输出:animal : eat
}
}

super注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super必须只能出现在子类的方法或者构造方法中
  3. super和this不能同时调用构造方法

对比this:

  • 代表的对象不同
    • this:本身调用者这个对象
    • super:代表父类对象的应用
  • 前提
    • this:没有继承也可以使用
    • super:只能在继承条件才可以使用
  • 构造方法
    • this():本类的构造
    • super():父类的构造

final关键字

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写

声明类:

1
final class 类名 {//类体}

声明方法:

1
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}

重写(Override)与重载(Overload)

重写(Override)

@Override 重写,是指两个方法具有相同的方法名称和参数(即方法签名),分别位于父类和子类中,重写允许子类提供已经提供其父类的方法的特定实现

重载(Overload)

@Overload 重载:是指一个类中允许存在多个同名方法,而这些方法的参数表不同(参数个数或者参数类型不同)

@Override 重写:需要有继承关系,子类重写父类方法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大但不能缩小(public > protected > default > private
  4. 抛出的异常:范围,可以被缩小,但不能扩大:ClassNotFoundException -> Exception(大)

多态

多态,即同一个方法可以根据发送对象的不同而采用多种不同的行为方式

还是以Student类继承Person类为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Demo04 {

public static void main(String[] args) {

// 一个对象的实际类型是确定的
// new Student();
// new Person();

// 可以指向的引用类型就不确定了:父类的引用指向子类
// Student能调用的方法都是自己的或者继承父类的!
Student s1 = new Student();
// Person父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();

// 对象能执行哪些方法,主要看对象左边的类型,与右边关系不大
s2.run(); // 子类重写了父类的方法,执行子类的方法
s1.eat(); // 子类自己调用自己的方法
((Student) s2).eat(); // 父类没有eat方法,要想调用必须强制类型转换为Student!
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// Student类
public class Student extends Person {

@Override
public void run() {
System.out.println("son");
}

// 子类独有方法
public void eat() {
System.out.println("eat");
}
}
1
2
3
4
5
6
7
// Person类
public class Person {

public void run() {
System.out.println("run");
}
}
  1. 父类引用指向子类的对象:Person s2 = new Student();
  2. 把子类转换为父类,向上转型
  3. 把父类转换为子类,向下转型:强制转换

多态存在的三个必要条件:

  1. 继承
  2. @Override 重写
  3. 父类引用指向子类对象:Parent p = new Child();

这里需要注意:有些方法不能被 @Override 重写

  1. static方法,属于类,它不属于实例
  2. final方法:final是常量的
  3. private方法

instanceof关键字

instanceof运算符的前一个操作符是一个引用变量,后一个操作数通常是一个类(可以是接口),用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是返回true,否则返回false。也就是说:使用instanceof关键字做判断时, instanceof 操作符的左右操作数必须有继承或实现关系

static关键字详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Student {

private static int age; // 静态变量
private double score; // 非静态变量

public static void main(String[] args) {

Student s1 = new Student();

System.out.println(Student.age);
System.out.println(Student.score); // 报错!
System.out.println(s1.age);
System.out.println(s1.score);

}
}

静态变量对于类,所有对象(实例)所共享,当直接使用类去调用得到说明这个变量是静态的

static代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Person {

// 2:赋初始值
{
System.out.println("匿名代码块");
}
// 1:只执行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();
}
}
1
2
3
4
5
6
静态代码块
匿名代码块
构造方法
===============
匿名代码块
构造方法

静态导入包

1
2
import static java.lang.Math.random;
import static java.lang.PI;

静态导入后,可以直接random()调用

抽象类

1
2
3
4
5
6
7
8
9
10
11
12
// abstract,抽象类
public abstract class Action {

// 约束
// abstract,抽象方法,只有方法名字,没有方法的实现
public abstract void doSomething();

// 1. 不能new这个抽象类,只能靠子类去实现它:约束!
// 2. 抽象类中可以写普通方法
// 3. 抽象方法必须在抽象类中

}
1
2
3
4
5
6
7
// 继承抽象类,抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非子类也是抽象类
public class A extends Action {
@Override
public void doSomething() {

}
}

子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类

接口的定义与实现

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有
  • 接口:只有规范,自己无法写方法

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类

1
2
3
4
5
6
7
8
9
10
11
12
// 接口都需要有实现类
public interface UserService {

// 常量 public static final,但一般没有在接口定义常量的
int AGE = 99;

// 接口中的所有定义都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
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 UserServiceImpl implements UserService {

@Override
public void add(String name) {

}

@Override
public void delete(String name) {

}

@Override
public void update(String name) {

}

@Override
public void query(String name) {

}
}

虽然java只能单继承,但是可以通过接口实现多继承

1
2
3
4
5
6
7
8
9
10
11
12
public interface UserService {

void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}

public interface TimeService {

void timer();
}
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
// 利用接口实现多继承
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() {

}

}
抽象类和接口的区别

抽象类和接口的区别:

  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
  3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口

内部类

内部类就是在一个类的内部定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,而A类相当B类来说就是外部类

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

参考