Featured image of post Quick Java

Quick Java

1 Java背景知识

1.1 JDK JRE JVM

  • JDK(开发工具包)
  • JRE(运行环境)运行时类库
  • JVM(Java虚拟机)

JDK:(Java Development Kit)

Java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。

JRE:(Java Runtime Environment)

Java运行环境,用于解释执行Java的字节码文件。

JVM: (Java Virtual Machine)

Java虚拟机,是JRE的一部分,负责解释执行字节码文件,是可运行Java字节码文件的虚拟计算机。

区别联系:(问答题会考可能)

JDK包含JRE,JDK和JRE中都包含JVM。JDK除了包含JRE还包含一些常用开发工具和基础类库。

JDK用于开发,JRE用于运行Java程序。

JVM是Java编程语言的核心并且具有平台独立性。

1.2 开发Java程序需要的3个步骤:

  1. 编写源文件
  2. 编译源文件生成字节码
  3. 加载运行字节码

1.3 Java程序运行过程:

1 javac: java源文件->class字节码文件(0,1) 2 java: 运行class文件

1.4 java程序语句执行的顺序

java程序语句执行的顺序包括4种基本控制结构:顺序结构、选择结构、循环结构、异常处理逻辑结构。 如果三个空(那就顺序 选择 循环)

2 编程基础

2.1 Java的基本语法

–方法格式

1
2
3
4
权限修饰符 返回值声明 方法名称(参数列表){
    方法中封装的逻辑功能;
    return 返回值;
} 

–权限修饰符

下表为Java访问控制符的含义和使用情况

访问级别 类内部 本包 子类 外部包
public
protected ×
default × ×
private × × ×

default也叫友好型

–注释

// 单行注释 /* 多行注释 / /* 文档注释 */

–关键字

关键字 含义
private 私有的
protected 受保护的
public 公共的
abstract 声明抽象
class
extends 继承、扩展
final 最终、不可改变
implements 实现
interface 接口
native 本地
new 新,创建
static 静态
strictfp 严格,精准
synchronized 线程、同步
transient 短暂
volatile 易失
程序控制语句 含义
break 跳出,中断
continue 继续
return 返回
do 运行
while 循环
if 如果
else 否则
for 循环
其它关键字 含义
instanceof 实例
switch 观察
case 返回观察里的结果
default 默认
try 捕获异常
catch 处理异常
throw 抛出一个异常对象
throws 声明一个异常可能被抛出
import 引入
package
boolean 布尔型
byte 字节型
char 字符型
double 双精度
float 浮点
int 整型
long 长整型
short 短整型
null
TRUE
FALSE
super 父类,超类
this 本类
void 无返回值
goto 跳转
const 静态
native 本地

–标识符

(你自己定义的一个东西的名字(比如类名,方法名,变量名,接口名,常量名…))

–注意事项定义的时候:

示识符:

由字母、数字、下划线(_)和美元符号($)组成。

不能以数字开头。

不能是Java中的关键字。

2.2 变量 常量

–变量的定义

按所属的数据类型划分:

  • 基本数据类型变量
  • 引用数据类型变量

按被声明的位置划分:

  • 局部变量:方法或语句块内部定义的变量

  • 成员变量:方法外部、类的内部定义的变量

    基本数据类型

类型 名称 含义 bit 字节数 值范围
整型 byte 字节 8 1字节 -128 到 127
整型 short 短整型 16 2字节 -32768 到 32767
整型 int 整型 32 4字节 -2,147,483,648 到 2,147,483,647
整型 long 长整型 64 8字节 -9223372036854775808 到 922337203685477580
浮点型 float 浮点数 32 4字节 有效位数15位
浮点型 double 双精度浮点数 64 8字节 有效位数15位
字符 char 字符 16 2字节 Unicode字符集
布尔型 boolean 布尔型 1 true/false

布尔型(boolean)的字节数在Java中并不是精确定义的,它是一个特殊的类型,用于表示真(true)或假(false)。在Java虚拟机(JVM)中,boolean的存储可能与其他基本类型不同,且其大小可能依赖于JVM的实现。在实际应用中,boolean通常用于逻辑判断,而不是进行数值计算。

引用数据类型

在 Java 中,引用类型(Reference Types)是指那些不是基本数据类型(如 intchardouble 等)的类型。引用类型包括以下几种:

  1. 类(Class):用户自定义的类,例如 public class A {...} 中的 A 类。

  2. 接口(Interface):定义了一组方法规范,但不提供实现的类型。

  3. 数组(Array):存储固定大小的相同类型元素的集合,例如 int[] numbers = new int[10];

  4. 枚举(Enum):一种特殊的类类型,其值是固定的常量,例如 enum Day { MONDAY, TUESDAY, WEDNESDAY, ... };

  5. 注解(Annotation):一种特殊的接口类型,用于提供元数据,例如 @Deprecated

  6. 字符串(String):虽然 String 在 Java 中是不可变的,但它是一个引用类型,用于表示字符序列。

–变量的类型转换

boolean 类型不能转换成任何其它数据类型。

自动类型转换

容量小的类型自动转换成容量大的数据类型 byte, short, int -> float -> long -> double byte, short, int 不会互相转换,它们三者在计算时会转换成 int 类型

显式类型转换

容量大的类型转换成容量小的数据类型时,要加上强制转换符(截断转换)

1
2
float b = 3.0f
a = (int)b

–变量的作用域

  1. 成员变量(全局变量 private int i=0;)或静态变量 private static String name=“list”) 在类体内定义的变量称为成员变量,它们作用域是整个类
  2. 局部变量 在一个方法或方法内代码块中定义的变量称为局部变量

–Java中的常量

(不怎么考)

常量不能被转换,例如常数

–注意事项

1
2
3
4
变量定义注意事项:
float a=13.3f    带上'f'
long a=222222222222L    带上'L'
char c= 'A'    带上' '

2.3 运算符

算数
1
2
+ - * / % ++ --
/ 取商 ;% 取余
赋值

=

关系

< >= <= == !=

逻辑

! && ||

& | 不怎么用

^ 按位异或运算符,逻辑异或运算符

位运算符(不会考)

~ << >> >>>

条件运算符

condition ? valueIfTrue : valueIfFalse;

  • condition:一个布尔表达式,其结果为 truefalse
  • valueIfTrue:如果 conditiontrue,则这个值会被选择。
  • valueIfFalse:如果 conditionfalse,则这个值会被选择。
1
2
int score = 85;
String grade = score >= 90 ? "A" : "B";

在这个例子中,如果 score 大于或等于90,grade 将被赋值为 "A";否则,它将被赋值为 "B"

2.4.1 选择语句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
if
else if	(接在if后面多重选择)
else
这三个与c语言基本相同
switch(XX) { 
//java特有 枚举 short byte int char String  
//C语言:字符,int
    case 1: XX;break;
    case 2: XX;break;
    default(可有可无): XX break;
}

2.4.2 java的循环

1
2
3
4
while(){}
for(){}
do{} while()
以上三种和c语言基本一样
1
2
3
for (ElementType element : collection) {
    // 在这里处理集合中的每个元素
}
  • ElementType:表示集合中元素的数据类型。
  • element:表示当前遍历到的集合元素的变量。
  • collection:表示要遍历的数组或集合。
1
2
3
4
5
6
7
8
9
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println(number);
}

List<String> words = Arrays.asList("Hello", "World", "Java");
for (String word : words) {
    System.out.println(word);
}

2.5 数组

-不允许在前面的括号写元素个数

2.5.1 多维数组初始化3种方式

–动态两种

java的多维数组每一维数可不同

1
2
3
4
5
1
int[][] arr = new int[3][]; //指定了行数,未指定列数
arr[0] = new int[3];//第0行3列
arr[1] = new int[2];//第1行2列
arr[2] = new int[1];//第2行1列
1
2
3
2
int[][] arr2 = new int[3][2];//同时指定行数和列数
arr[0][0] = 33;//单独对元素赋值

–静态一种

1
2
int arr4[][] = new int[][]{{1, 2, 3}, {2, 3}};
//第0行是{1,2,3},第1行是{2,3}

不赋值默认元素为0

一般来说初始化时都默认括号在数组名前,这是Java的风格,当然反过来也一样可行(c语言风格)

2.5.2 数组的常见操作

声明数组:

1
int arr[]

数组初始化:

1
2
int[] arr={1,2,3,4};
int[] arr=new int[]{1,2,3,4};

查看数组长度:

1
2
arr.length;
返回值是整数反映了数组中第一维元素的个数

for each 循环:

1
2
3
for(int a:arr){
    System.out.println(a);
}

数组拷贝:

1
2
3
4
int[] arr2=arr1;

int[] arr2=Arrays.copyOf(arr, arr.length(自定义长度));
arr2会复制arr1 length长度的元素

数组排序:

1
2
Arrays.sort(arr);
默认从小到大排序

将int数组转换为字符串:

1
2
Arrays.toString(arr);
连括号一起转换成字符串了

2.6 输入输出

输入

1
2
Scanner s = new Scanner(System.in);
//先创建了一个Scanner对象s,用于从System.in(标准输入流,即键盘输入)读取数据。

在Java中,Scanner 类的 next() 方法用于从输入流中读取下一个完整的 token。Token 通常是输入中的一个单词,由空白字符(如空格、制表符或换行符)分隔。next() 方法会读取并返回一个字符串,直到遇到下一个空白字符,但不包括这个空白字符。(类比scanf)

1
2
3
4
String word = s.next(); 
// 从标准输入读取一个单词
System.out.println("输入的单词是: " + word);
//输出

如果需要读取包含空格的字符串,应该使用 nextLine() 而不是 next()

它将读取输入直到遇到换行符(\n),并将换行符之前的所有内容(包括空格)作为字符串返回。

1
String sentence = s.nextLine(); // 读取整行,包括空格

在s.next()的基础上,有:

1
2
3
4
5
6
s.nextInt();
//读取用户输入的下一个整数
s.nextFloat();
//读取用户输入的下一个浮点数。这可以是单个数字、小数或科学记数法表示的数字
//即:
s.next类型名();

Scanner 类的 hasNext() 方法用于检查输入流中是否还有更多的输入。这是一个非常有用的功能,尤其是在处理不确定数量的输入时,比如在读取用户输入直到用户决定停止时。

1
2
3
4
5
6
7
8
Scanner s = new Scanner(System.in);
while (s.hasNext()) {
    String input = s.next();
    if ("end".equals(input)) {
        break; // 结束循环
    }
    System.out.println("处理输入: " + input);
}

同理有:hasNextLine() hasNextFloat()等方法检验有无特定类型的输入

这里插入一下字符串的比较equals()方法

1
2
3
4
5
boolean areEqual = str1.equals(str2); 
//若str1与str2内容相同,返回true,反之返回false
//注意:空值检查
//如果 equals 方法的参数是 null,那么在没有进行空值检查的情况下直接调用会导致 NullPointerException。
//因此,通常在调用 equals 方法之前,会先检查参数是否为 null。

输出

在Java中,输出数据到控制台或文件可以通过多种方式实现。以下是一些输出方法:

  1. System.out.printSystem.out.println:(常用)

    • System.out.print:将数据打印到标准输出(通常是控制台),但不换行。
    • System.out.println:将数据打印到标准输出,并在末尾添加一个换行符。
    1
    2
    
    System.out.print("Hello, ");
    System.out.println("World!");
    
  2. System.out.printf

    • 用于格式化输出,类似于C语言中的 printf 函数。可以指定输出格式和宽度等。
    1
    
    System.out.printf("The value of pi is: %.2f%n", Math.PI);
    
  3. System.out.format

    • 类似于 System.out.printf,但返回 String 对象而不是打印到控制台。
    1
    
    String formattedString = System.out.format("The value of pi is: %.2f%n", Math.PI);
    
  4. PrintStream

    • System.out 是一个 PrintStream 对象,提供了更多的方法来控制输出,如 print, println, printf, format 等。
  5. BufferedWriter

    • 用于将文本写入字符输出流,可以提高写入性能,特别是当写入大量数据时。
    1
    2
    3
    4
    
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
    writer.write("Hello, World!");
    writer.newLine(); // 写入换行符
    writer.flush(); // 清空缓冲区
    
  6. PrintWriter

    • 用于打印格式化表示的字符到控制台或文件。
    1
    2
    3
    
    PrintWriter writer = new PrintWriter(System.out, true);
    writer.println("Hello, World!");
    writer.flush(); // 清空缓冲区
    
  7. FileWriter

    • 用于写入字符到文件。
    1
    2
    3
    
    FileWriter writer = new FileWriter("output.txt");
    writer.write("Hello, World!");
    writer.close(); // 关闭文件写入器
    
  8. Files.write (Java 7+):

    • 用于将字节数据写入文件,可以指定字符编码。
    1
    2
    
    Path path = Paths.get("output.txt");
    Files.write(path, "Hello, World!".getBytes(StandardCharsets.UTF_8));
    
  9. Logger

    • Java的日志记录框架,用于记录应用程序的日志信息。
    1
    2
    
    Logger logger = Logger.getLogger("MyLogger");
    logger.info("Hello, World!");
    
  10. StringBufferStringBuilder

    • 用于在内存中构建字符串,特别是当需要多次修改字符串内容时。
    1
    2
    3
    
    StringBuilder sb = new StringBuilder("Hello, ");
    sb.append("World!");
    System.out.println(sb.toString());
    

选择哪种输出方法取决于你的具体需求,比如是否需要格式化输出、是否需要写入文件、是否需要考虑性能等因素。

2.7.1 类与对象

  • 概念
  • 三大特征
  1. 封装 “通过 private、default、protected、public 关键字实现属性或方法的封装,仅对外提供公共访问方式。” “高内聚、低耦合”

    封装的好处:

    • 实现数据和方法的隐藏
    • 实现信息隐藏,允许外部对类有限的访问,开发者可以自由的改变类的内部实现
    • 提高了代码的重用性
  2. 继承

    通过 extends。 两个好处:

    • 代码重用了。
    • 通过继承,实现对现实世界更加准确的建模。
  3. 多态

    多态是指允许不同类的对象对同一消息做出响应,即同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。在Java中多态的实现方式:接口实现,继承父类进行方法重写。同一个类中进行方法重载,父类引用指向子类对象。

2.7.2 类与对象 (重点)

  • 关系

  • 实例化(对象的创建)

通过 new 关键字创建 比如

1
2
Student zhangchunhui = new Student();
zhangchunhui.setAge(20);
1
2
3
4
5
6
class Student{
    private int age;
    public static void setAge(int age){
        this.age = age;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Stu{
    //1 属性设为私有
    private int age;
    //2 方法 get set 你自己定义的
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return this.age;
    }
    //我自己定义的方法
    public void myPrint() {
        System.out.println("nihao");
    }
    //3 构造函数
	public Stu() {
	}
    
	public Stu(int age) {
    	this.age = age;
        //类内用this指代该类
	}
}

若使用无参数构造函数

1
2
Stu student1 = new Stu(); // 创建了一个Stu对象,但是age属性没有被初始化
student1.setAge(25); // 之后可以手动设置age属性的值

若使用带参数构造函数

1
Stu student2 = new Stu(20); // 创建了一个Stu对象,并且age属性被初始化为20

类的定义(格式,注意事项)

1
2
3
4
[修饰符] class 类名 [extends 父类名] [implements 接口名]{
    // 类体,包括类的成员变量和成员方法
}
//[]表示可选

2.8 类的继承

Object类

Object类是所有类的父类,里面有很多方法 clone getClass toString equals hashCode notify notifyAll wait finalize

  1. getClass方法 获取运行时类型,返回值为Class对象
  2. hashCode方法 返回该对象的哈希码值,是为了提高哈希表的效率(Hashtable)
  3. equals方法 判断两个对象是否相等,在Object类中equals就是使用==去判断,所以在Object的子类中,如果equals相等的两个对象,hashCode一定相等,实现不同的比较。
  4. clone方法 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递。我们有时候不希望在方法里修改参数,这就需要在类中重写clone方法。 如果在clone方法中调用super.clone()方法需要实现Cloneable接口,否则会抛出CloneNotSupportedException。 此方法只实现了一个浅层拷贝,对于基本类型字段成功拷贝,但是如果是数组等对象,只做了浅拷贝,也就是只复制了对象的引用,所以需要自己重写clone方法进行深层拷贝。
  5. toString方法 返回一个String字符串,用于描述当前对象的信息,可以重写该方法返回对自己有用的信息,默认返回的是当前对象的类名+hashCode的16进制数字。
  6. wait方法 多线程中用到的方法,作用是让当前线程进入等待状态,同时也会释放当前线程所持有的锁。直到其他线程调用此对象的notify()方法或notifyAll()方法,当前线程才会被唤醒。
  7. notify方法 多线程时用到的方法,唤醒该对象等待的某个线程
  8. notifyAll方法 多线程时用到的方法,唤醒该对象等待的所有线程
  9. finalize 对象在被垃圾收集器回收前一定会调用finalize方法,对象被释放前最后的挣扎,因为无法确定该方法什么时候被调用,很少使用。

–类的继承格式

1
2
3
4
5
class 父类 {
}

class 子类 extends 父类 {
}

–继承了之后有父类(非私有private)的属性或方法,可直接调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Animal {
    public String name;
    private int id;
    public Animal(String myName, String myId) {
         // 初始化属性值
    }
    public void eat() { }
    public void sleep() {
        System.out.println("晚上了我要睡觉")
    }
}

public class Owl extends Animal{
}

—重写父类方法

子类可以重写父类的同名方法,以根据需求覆盖原方法

1
2
3
4
5
public class Penguin extends Animal{
	    public void sleep() {
        System.out.println("白天了我要睡觉")
    }
}

2.9 类的封装

将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供getter/setter的方法来对隐藏的信息进行操作和访问。

getter setter

封装的实现步骤:

(1) 将成员属性的可见性设为(private)

(2) 创建getter/setter方法(用于属性的读写)(通过这两种方法对数据进行获取和设定,对象通过调用这两种方法实现对数据的读写)

(3) 在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)

 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
public class Person {
    private String name;
    private int age;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        if(age < 0){
            System.out.println("你的年龄不合法请重新输入")
        }
        else{
        this.age = age;
        }
    }

    public void setName(String name) {
        this.name = name;
    }
}
//通过方法来访问或者修改私有private的属性

2.10 构造方法(重点)

–定义

主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

一个类可以有多个构造函数,可根据其参数个数的不同或参数类型的不同来区分它们,即构造函数的重载。

–重载

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public Animal2(String name, int myid) {
    this.name = name;
    this.id = myid;
}

public Animal2(String name) {
    this.name = name;
}

public Animal2(int id2) {
    this.id = id2;
}

2.11 方法的重载 和 重写

–回顾一下方法定义格式:

1
2
3
4
权限修饰符 返回值声明 方法名称(参数列表){
    方法中封装的逻辑功能;
    return 返回值;
}

重载(Overloading):

发生在同一个类中,当多个方法有相同的名称但参数列表不同(与返回值类型、修饰符无关)时,这些方法就是重载的。

重载的目的是为了提供相同功能但使用不同参数的方法,以提高代码的可读性和灵活性。

示例见下或2.10

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

    // 重载方法1:两个整数相加
    public int add(int a, int b) {
        return a + b;
    }

    // 重载方法2:三个整数相加
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 重载方法3:两个浮点数相加
    public double add(double a, double b) {
        return a + b;
    }
}

重写(Overriding):

发生在子类和父类之间,当子类有一个与父类方法签名(方法名称和参数列表)完全相同的方法时,子类的方法就重写了父类的方法。

重写的目的是为了提供特定于子类的行为,即子类可以根据自己的需要改变父类方法的行为。

实例见 2.8

重写的注意事项

  1. 重写的方法必须要和父类一模一样(包括返回值类型、方法名、参数列表)。
  2. 重写的方法可以使用 @Override 注解来标识。
  3. 子类中重写的方法的访问权限不能低于父类中方法的访问权限。权限修饰符的顺序是:private < 默认(什么都不写) < protected < public

2.12.1 this 关键字

Java 中为解决变量的命名冲突和不确定性问题,引入关键字 this 代表其所在方法的当前对象的引用:

  1. 构造方法中指该构造器所创建的新对象:
1
2
3
4
5
6
7
8
public class B {
    A a; // A是另一个类,算一个类型
    // 构造方法,接收一个 A 类型的参数
    public B(A a) {
        this.a = a;
        // 使用 this 来区分成员变量 a 和参数 a
    }
}
  1. 方法中指调用该方法的对象:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Baby {
    public void wakeUp() {
        System.out.println("宝宝醒啦");
    }

    public void eat() {
        this.wakeUp(); // 调用当前对象的wakeUp方法
        System.out.println("吃东西");
    }
}
  1. 在类本身的方法或构造器中引用该类的实例变量(全局变量)和方法:
1
2
3
4
5
public void setName(String name) {
    this.name = name; 
    // 使用this关键字来区分成员变量和方法参数
    //this.name是成员变量,name是方法参数
}

–注意

this 只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现 this

–原因:static 方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。

2.12.2 super 关键字

一句话概括:super 关键字主要存在于子类方法中,用于指向子类对象中的父类对象;可以访问父类的属性、函数以及构造函数。

  1. 当子类和父类存在着同名的成员(包括变量和方法)时,在子类中默认是访问子类的成员,可以通过 super 关键字指定访问父类的成员。

  2. 默认会先调用父类无参的构造方法,可以通过 super 关键字指定调用父类的构造方法。

示例

假设我们有一个父类 Animal 和一个子类 Dog,我们可以这样使用 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
class Animal {
    String name;
    
    // 父类的构造方法
    public Animal() {
        System.out.println("Animal's constructor");
    }
    
    // 父类的方法
    public void makeSound() {
        System.out.println("Some generic animal sound");
    }
}

class Dog extends Animal {
    // 子类的构造方法
    public Dog() {
        super(); // 调用父类的无参构造方法
        System.out.println("Dog's constructor");
    }
    
    // 子类重写的方法
    @Override
    public void makeSound() {
        System.out.println("Woof woof");
    }
    
    // 使用super调用父类的makeSound方法
    public void specificSound() {
        super.makeSound(); // 调用父类的makeSound方法
        System.out.println("Dog's specific sound");
    }
}

在这个例子中,super 关键字用于在子类 Dog 中调用父类 Animal 的构造方法和 makeSound 方法。这展示了如何在子类中访问和使用父类的成员。

2.13.1 static 关键字

–静态变量

1
private static String str1 = "staticProperty";

–静态方法

1
2
3
4
5
public static void print2() {
    System.out.println(str1);
    System.out.println(str2);
    print1();
}

–静态代码块

1
2
3
static {
    static int a = 3;
}
  1. static 修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要 new 出一个类来。

  2. static 修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要 new 出一个类来。

平时要使用类中的变量或者方法都要先new实例化一个类。

2.13.2 final关键字

final:用于声明常量、最终类或最终方法。

–修饰变量

  1. 基本类型变量使用 final 修饰了就不可变了
  2. 对于引用类型变量被 final 修饰了;引用变量引用不可变(就整个引用变量不可变),但是引用对象的内容可以改变。

举例

final修饰数组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class FinalArrayExample {
    public static void main(String[] args) {
        final int[] numbers = {1, 2, 3, 4, 5};
        
        // 修改数组中的元素是允许的
        numbers[0] = 10;
        
        // 尝试重新赋值,这将导致编译错误
        // numbers = new int[]{6, 7, 8}; // 错误:不能将变量 numbers 赋值

        // 输出修改后的数组
        System.out.println(Arrays.toString(numbers)); // 输出: [10, 2, 3, 4, 5]
    }
}

在这个例子中,数组 numbersfinal 修饰,这意味着数组的引用不能被改变指向另一个数组。但是,数组中的元素可以被修改。

–修饰类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class FinalObjectExample {
    public static void main(String[] args) {
        final A obj = new A();
        
        // 修改对象的属性是允许的,如果属性不是 final 的
        obj.a = 4; // 假设 A 类中的 a 不是 final
        
        // 尝试重新赋值,这将导致编译错误
        // obj = new A(); // 错误:不能将变量 obj 赋值

        // 输出对象的属性值
        System.out.println(obj.a); // 输出: 4
    }
}

class A {
    int a = 3;
}

注意

final 修饰的类,不能被继承()

–修饰方法

final 修饰的方法 不能被重写,但是子类可以用父类中 final 修饰的方法;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
final class FinalClassExample {
    // final 类不能被继承
    // 子类继承 FinalClassExample 是不允许的

    public final void display() {
        System.out.println("Hello, World!");
    }

    // final 方法不能被子类重写
    // 子类重写 display 方法是不允许的
}

// 尝试创建子类将导致编译错误
// class SubClass extends FinalClassExample { }

2.14 抽象类

1
2
3
4
5
6
public abstract class Action {
    public abstract void doSomething(); // 抽象方法
    public void test() {
        // 方法体
    }
}

在这段代码中,Action 类被声明为抽象类,使用 abstract 关键字。这意味着 Action 类不能被实例化,它只能作为其他类的父类。

抽象类可以包含抽象方法和具体方法。

抽象方法也使用 abstract 关键字声明,它们没有方法体,必须在子类中被实现。在这个例子中,doSomething 是一个抽象方法,而 test 是一个具体方法,它提供了一个方法体。

子类继承 Action 类时,必须实现 doSomething 方法,即要重写 doSomething 方法并添加具体的方法体。

2.15 接口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public interface UserService {
    // 接口中的所有定义的方法默认都是抽象的(public abstract)
    // 变量只能为 public static final 类型的
    // public abstract void add(); // 等效于 void add();
    
    // int age = 99; // 等效于 public static final int age = 99;
    int age = 99;
    
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

在 Java 中,接口(interface)是一种特殊的抽象类型,它可以包含抽象方法和常量。接口中的方法默认是 public abstract 的,这意味着它们没有方法体,必须由实现接口的类来提供具体实现。接口中的变量默认是 public static final 的,这意味着它们是常量,并且必须在声明时初始化。

–区别

  1. 接口要被子类实现,抽象类要被子类继承。
  2. 接口中变量全为公共静态常量,抽象类中可有普通变量。
  3. 接口中全为抽象方法的声明,抽象类中可以有具体方法的实现。
  4. 接口中不可以有构造函数,抽象类中可以有构造函数。
  5. 一个类可实现多个接口,而抽象类只能被单继承
  6. 接口中方法为抽象方法,而抽象类中也可有非抽象方法。

示例

1
2
3
4
5
6
//定义接口
public interface Vehicle {
    void startEngine();
    void stopEngine();
    void honk();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//实现接口
//一旦你决定用一个类实现一个接口,你必须实现其所有的抽象方法
public class Car implements Vehicle {
    @Override
    public void startEngine() {
        System.out.println("Car engine started.");
    }

    @Override
    public void stopEngine() {
        System.out.println("Car engine stopped.");
    }

    @Override
    public void honk() {
        System.out.println("Car horn honked.");
    }
}
1
2
3
4
5
6
7
8
9
//调用方法
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.startEngine();
        myCar.honk();
        myCar.stopEngine();
    }
}
Licensed under CC BY-NC-SA 4.0
© 2023-2025 Ch0ser. All Rights Reserved.
使用 Hugo 构建
主题 StackJimmy 设计