[关闭]
@SovietPower 2022-05-08T13:29:50.000000Z 字数 11583 阅读 1122

Java 笔记

学习笔记



作业部落链接:https://www.zybuluo.com/SovietPower/note/2200494
参考:
https://www.runoob.com/java/java-tutorial.html

安装

下载:https://www.oracle.com/java/technologies/downloads/#jdk17-windows
可以直接用exe安装,否则还要添加环境变量。
cmd中测试java -version, javac命令。

使用vscode

安装插件 Extension Pack for Java。
setting.json里添加插件设置:

  1. "java.import.gradle.java.home": "F:\\Programs\\Java\\jdk-17.0.2",
  2. "java.configuration.runtimes": [
  3. {
  4. "name": "JavaSE-17",
  5. "path": "F:\\Programs\\Java\\jdk-17.0.2"
  6. },
  7. {
  8. "name": "JavaSE-1.8",
  9. "path": "F:\\Programs\\Java\\jdk1.8.0_321"
  10. }
  11. ]

测试
Ctrl+Shift+P,输入java:create java Project,选择No build tools,输入路径、项目名,可创建项目。
点击项目src下的App.java,在主类处可Run运行该项目的main
使用Code Runner也可以运行单个Java。


简介

https://www.runoob.com/java/java-intro.html

Java为半解释半编译型语言。通过javac.java编译为字节代码的.class文件,通过java运行.java文件。

JDK(Java Development Kit ):编写Java程序的程序员使用的软件,为程序员提供一些已经封装好的 java 类库。
JRE(Java Runtime Environment):运行Java程序的用户使用的软件。
Server JRE (Java SE Runtime Environment):服务端使用的 Java 运行环境。
SDK(Software Development Kit):软件开发工具包,在Java中用于描述1998年~2006年之间的JDK。
DAO(Data Access Object):数据访问接口,数据访问,顾名思义就是与数据库打交道。
MVC(Model View Controller):模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法。


语法

基础语法及规范

https://www.runoob.com/java/java-basic-syntax.html

文档注释/说明注释:https://www.runoob.com/java/java-documentation.html

类、对象、文件规则

https://www.runoob.com/java/java-object-classes.html

基本数据类型、常量、字面量

https://www.runoob.com/java/java-basic-datatypes.html

String不是基本数据类型。使用时首字母也应大写。
"str"表示字符串,'c'表示字符。

使用字面量时,前缀0表示 8 进制,而前缀0x表示 16 进制, 如:

  1. int decimal = 100;
  2. int octal = 0144;
  3. int hexa = 0x64;

boolean 类型为逻辑类型,值为逻辑值;其它类型为数值类型,值为数值。逻辑类型和数值类型间不可转换,逻辑值和数值间无法比较(会CE)。
所以不可用while(1)等,如果x不是boolean,也不能用if(x), if(!x),应if(x!=0), if(x==0)

注意对于对象来说==是比较地址,字符串应使用equals比较。
但基本类型直接用==,如charA==charB

数据类型转换规则:
1. 不能对 boolean 类型进行类型转换(同样不能给 boolean 赋值其它类型的值)。
2. 不能把对象类型转换成不相关类的对象。
3. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换;反之不用,会自动转换。
4. 转换过程中可能导致溢出或损失精度。
5. 浮点数到整数的转换是通过截断(舍弃小数)得到,而不是四舍五入。

比int类型小的数值类型做运算时,java在编译时会将它们统一转换成int,即结果也为int。当比int类型大的数值类型做运算时,会将它们转换成它们中最大的类型。

泛型

泛型是假的,实际上全部都是Object,所以java容器里只能是装箱后的引用类型如Integer/Boolean等,不能是值类型如int/boolean之类的,C#就没这个问题,值类型可以直接放进容器。

变量

Java的变量类型:

类变量:独立于方法之外的变量,与类绑定,用 static 修饰。
有默认值(0, false 或 null)。可在类中任意一个位置声明。
是属于某个对象的属性,创建实例对象后,其中的实例变量才会被分配空间。
final修饰的类变量可在静态方法中赋值(声明时不赋值)。

实例变量:独立于方法之外的变量,与对象实例绑定,没有 static 修饰。
有默认值(0, false 或 null)。可在类中任意一个位置声明。
不属于某个实例对象,属于类。只要程序加载了类的字节码,静态变量就会被分配空间,无需创建实例对象。

局部变量:类的方法中的变量。
访问修饰符不能用于局部变量;在栈上分配;没有默认值,所以局部变量被声明后,必须初始化,否则不可使用(会CE)。

修饰符

https://www.runoob.com/java/java-modifier-types.html#protected-desc

switch

Number, Character

一般使用的 byte、int、long、double 等,是内置数据类型。
因为有时需将内置数据类型作为对象来使用,所以 Java 为每一个内置数据类型提供了对应的包装类:Integer、Long、Byte、Double、Float、Short,它们都是 Number 的子类。Number 类属于 java.lang 包(会自动导入java.lang.*)。
Character 是 char 的包装类。
包装类对象为该数据类型提供了许多方法。但是不包装也可使用,如char c; Character.isDigit(c)
这种由编译器特别支持的包装称为装箱。当内置数据类型被当作对象使用时,编译器将内置类型装箱为包装类。当使用对象的数值时,编译器把对象拆箱为内置数据类型

非 new 生成的 Integer 变量(直接赋值)与new Integer()生成的变量地址不同。非 new 生成的 Integer 变量指向的是 java 常量池中的对象,而new Integer()生成的变量指向堆中新建的对象(String 同理)。
使用obj = Number/Character.valueOf(x)x为数值)新建对象,与直接赋值的非 new 生成对象相同(规则也相同,内会重用,否则不会)。

对于在(默认)内的值,被装箱后,该对象会被放在内存里进行重用(即使有多个相同数值的对象,它们的实际地址也是相同的),即已经预定义了这些数值的对象。
但是如果超出了这个区间,系统会重新new一个对象,此时多个相同数值的对象存在不同的位置。
当对象和数值进行比较时,会进行拆箱比较其数值。

  1. public class A {
  2. public static void main(String[] args)
  3. {
  4. Integer i = new Integer(1);
  5. Integer j = 1;
  6. Integer k = Integer.valueOf(1);
  7. System.out.printf("%b %b %b\n", i == j, i == k, j == k);
  8. Integer a = 128, b = 128;
  9. Integer c = 127, d = 127;
  10. int x = 1, y = 1;
  11. System.out.printf("%d %d %d %d\n", a, b, c, d);
  12. System.out.println(a == b);
  13. System.out.println(a.equals(b));
  14. System.out.println(c == d);
  15. System.out.println(x == y);
  16. System.out.println(a == 128);
  17. }
  18. }
  19. /*
  20. 输出:
  21. false false true
  22. 128 128 127 127
  23. false
  24. true
  25. true
  26. true
  27. true
  28. */

String

Java 的 String 为一个类,而不是基本数据类型。

String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:

  1. public class A {
  2. public static void main(String[] args)
  3. {
  4. String s1 = "abc"; // String 直接创建
  5. String s2 = s1; // 相同引用
  6. String s3 = new String("abc"); // String 对象创建
  7. System.out.printf("%b %b %b\n", s1 == s2, s1 == s3, s2 == s3);
  8. System.out.printf("%b %b %b\n", s1.equals(s2), s1.equals(s3), s2.equals(s3));
  9. }
  10. }
  11. /*
  12. 输出:
  13. true false false
  14. true true true
  15. */

与基本数据类型不同,String 对象保存的值不可修改,只能新建一个对象。
如需修改,使用StringBuffer 和 StringBuilder 类

使用String.concat()+连接字符串(包括字符粗常量)。
String.format()可创建格式化字符串(用法与printf相同,但返回字符串)

字符串常量之间进行+,会直接计算得出常量结果。值相同的常量只会创建一次,所以它们地址相同。
但对字符串常量使用concat,或对字符串变量使用+(即使是与常量),不会直接进行计算,而是会创建 StringBuilder 或 StringBuffer 对象,使用append连接。这些对象中的每个都有自己的地址。
这两种方式得到的相同字符串,地址也是不同的。

  1. public class HelloWorldA {
  2. public static void main(String[] args)
  3. {
  4. String t1="a"+"b"+"c";
  5. String t2="abc";
  6. System.out.printf("t: %b %b\n", t1==t2, t1.equals(t2));
  7. String s1 = "ab";
  8. String s2 = "abc";
  9. String s3 = s1 + "c";
  10. System.out.printf("s: %b %b %b\n", s1 == s2, s1 == s3, s2 == s3);
  11. System.out.printf("s: %b\n", s2.equals(s3));
  12. String q1 = "a".concat("b").concat("c");
  13. String q2 = "a"+"b"+"c";
  14. String q3 = "abc";
  15. System.out.printf("q: %b %b %b\n", q1 == q2, q1 == q3, q2 == q3);
  16. System.out.printf("q: %b %b %b\n", q1.equals(q2), q1.equals(q3), q2.equals(q3));
  17. }
  18. }
  19. /*
  20. 输出:
  21. t: true true
  22. s: false false false
  23. s: true
  24. q: false false true
  25. q: true true true
  26. */

常用函数

若要获取单个字符,不能用[],需用charAtsubstring
String不可迭代(for遍历),所以遍历只能枚举charAt(i)

StringBuffer 和 StringBuilder todo

https://www.runoob.com/java/java-stringbuffer.html

数组

https://www.runoob.com/java/java-array.html

使用某个类型[]创建定长数组。

List

https://www.runoob.com/java/java-arraylist.html
https://www.liaoxuefeng.com/wiki/1252599548343744/1265112034799552

动态数组。
有两个子类:ArrayListLinkedList
前者类似vector,用数组实现;后者用链表实现。
所以前者可以随机读取,但插入删除复杂度高;后者随机读取的复杂度高,但插入删除可以O(1)。

创建list时不指定类型,则为Object,可存任意类型。使用时需自己转换类型。
List list = new ArrayList();
如果显式指定类型,则程序运行时会进行类型检查。

map同理:Map map = new HashMap();

方法

参数传递:https://www.zhihu.com/question/31203609
Java 只有值传递(因为没有指针的概念),基本类型传递值本身,其它对象(包括String)传递指向对象的地址(类似引用传递)。
String未提供setter或改变自身的方法(如append),在赋值时会创建新的String对象赋给参数,所以即使是传递了地址,原有对象也不会因参数改变而改变。
注意,很多对象参数使用=赋值,并不会改变原有对象,除非用改变自身(而不是返回新的)的相应方法。

错误 异常

https://www.runoob.com/java/java-exceptions.html

检查型异常(Checked Exception)
在Java中所有不是RuntimeException派生的Exception都是检查型异常。当函数中存在可能(?)抛出检查型异常的操作时(如打开文件),该函数的函数声明中必须包含throws,或必须捕获该异常,否则程序终止。如是前者,则调用该函数的函数必须对该异常进行处理,否则也应在函数后声明throws
编译器会检查这类异常,如果在编译时没有处理这些异常(没有throws也没catch),则无法通过编译。可以强制开发者在运行前就处理。
处理异常的方式就是两种:throwstry catch
如果异常用catch没匹配到相应类型的错误,则该异常算作没被捕获,程序终止。
catch内可以为空,也算捕获并处理了该类型错误(即忽略)。

非检查型异常/运行时异常(Unchecked Exception/Runtime Exception)
编译器不会检查这类异常。这类异常一般可以避免,如除0、数组越界、访问null,所以不强制catch
而且一般无法恢复或不可捕获,所以一般让程序直接终止。

使用throw new Exception()主动抛出任意异常。

try-with-resources
JDK7 之后,Java 新增的 try-with-resource 语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
JDK7 之前所有被打开的系统资源,比如流、文件或者 Socket 连接等,都需要被开发者手动关闭,否则会造成资源泄露将。

  1. try (resource declaration) {
  2. // 使用的资源
  3. } catch (ExceptionType e1) {
  4. // 异常块
  5. }

以上的语法中 try 用于声明和实例化资源,catch 用于处理关闭资源时可能引发的所有异常。
declaration中就要给变量赋值,且之后不能更改。


面向对象

继承

类不能继承多个类(不能多继承),但可以链式继承(可以多重继承)。
类可以继承多个接口interface
使用extends [class]继承一个类,使用implements [interface1, interface2, ...]继承多个接口。
super表示当前对象的父类,可用来访问父类成员。this表示当前对象。

子类拥有父类的非私有属性和方法。

子类不继承父类的构造器(构造方法或构造函数),但它会调用(隐式或显式)父类的构造器。如果父类的构造器带有参数,则必须在子类构造器中显式地通过super调用父类的构造器,并传递适当的参数。
如果父类构造器没有参数,则在子类构造器中不需要使用super调用父类构造器,系统会自动调用父类的无参构造器。

继承提高了类之间的耦合性。耦合度高会造成代码之间的联系紧密,代码独立性差。
所有的类都继承于java.lang.Object

final

final可修饰变量(类属性、对象属性、局部变量、形参)、方法(类方法、对象方法)和类。
final声明的类为最终类,不能被继承(但其属性、方法并不一定是final的)。
final修饰的方法不能被子类重写。

override todo

https://www.runoob.com/java/java-override-overload.html

抽象

https://www.runoob.com/java/java-abstraction.html

抽象类abstract class不能被实例化成对象,其他与一般类相同。抽象类只用来被继承。一个类只能继承一个抽象类。
抽象方法不能被直接调用,是一个必须被子类实现的方法的占位符。抽象方法只有声明,没有函数体,具体需由子类实现。

如果一个类包含抽象方法,那么该类必须是抽象类。但抽象类可以有非抽象方法(与一般类相同)。
任何子类必须重写父类的抽象方法,或声明自身为抽象类。
构造方法,类方法(静态方法)不能声明为抽象方法。


代码规范

https://blog.csdn.net/qq_42988868/article/details/121633508


数据库 mysql

下载驱动包:https://dev.mysql.com/downloads/windows/installer/8.0.html
选择 Platform Independent 的zip,解压后得到 jar 库文件。

下面这个方法并没有成功:
新建系统变量CLASSPATH,添加解压后的路径(如果之前已有路径,则需用;与前面隔开)

在工作目录(或者任意目录,或者项目本身的libs目录),新建一个文件夹libs(名字任意),把解压后文件夹里的jar文件放进去。
vscode左边,有JAVA PROJECTS,在Referenced Libraries中添加保存的jar文件,即可导入。

测试代码
(可以用try-with-resources

  1. import java.sql.*;
  2. public class Exercise
  3. {
  4. static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // 驱动名
  5. static final String DB_URL = "jdbc:mysql://localhost:3306/db_name?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; // 数据库 URL
  6. public static void main(String... args)
  7. {
  8. String username = "root";
  9. String password = "111";
  10. Connection conn = null;
  11. Statement stmt = null;
  12. try
  13. {
  14. // 注册 JDBC 驱动
  15. Class.forName(JDBC_DRIVER);
  16. // 打开链接
  17. System.out.println("Connecting");
  18. conn = DriverManager.getConnection(DB_URL, username, password);
  19. // 执行查询
  20. System.out.println("Instancing Statement");
  21. stmt = conn.createStatement();
  22. String sql;
  23. sql = "SELECT id, name FROM test";
  24. ResultSet rs = stmt.executeQuery(sql);
  25. while(rs.next())
  26. {
  27. int id = rs.getInt("id");
  28. String name = rs.getString("name");
  29. System.out.print("ID: " + id);
  30. System.out.println(", name: " + name);
  31. }
  32. // 关闭
  33. rs.close();
  34. stmt.close();
  35. conn.close();
  36. }
  37. catch(SQLException se)
  38. {
  39. // 处理 JDBC 错误
  40. se.printStackTrace();
  41. }
  42. catch(Exception e)
  43. {
  44. // 处理 Class.forName 错误
  45. e.printStackTrace();
  46. }
  47. finally
  48. {
  49. // 关闭资源
  50. try {
  51. if(stmt!=null) stmt.close();
  52. }
  53. catch(SQLException se2) {
  54. // do nothing
  55. }
  56. try {
  57. if(conn!=null) conn.close();
  58. }
  59. catch(SQLException se) {
  60. se.printStackTrace();
  61. }
  62. }
  63. System.out.println("finish!");
  64. }
  65. }

allowPublicKeyRetrieval=true:允许客户端从服务器获取公钥。
默认建立 SSL 连接,如果不需要可显示关闭。
新版的mysql需要指定时区serverTimezone

运行
使用插件给的代码里的Run。
如果自己输命令,或用Code Runner,需要像Run给的指令一样去写。
如:java -cp 'C:\Users\LENOVO\AppData\Local\Temp\cp_ee1zqjoxovyu9bi9ynkr1649l.jar' Exercise
需要用-classpath-cp指定驱动jar包的路径,但这个路径需要是vscode生成的,不能自己指定实际的路径比如F:\Codes\Java\DB\libs\mysql-connector-java-8.0.28.jar,否则会java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver,或错误: 找不到或无法加载主类,不知道为什么。

其它

错误码
见mysql驱动包下的:mysql-connector-java-8.0.28\src\main\core-api\java\com\mysql\cj\exceptions\MysqlErrorNumbers.java,里面定义了SQLException.getErrorCode()常数。
import com.mysql.cj.exceptions.MysqlErrorNumbers;后,也可使用如MysqlErrorNumbers.ER_ACCESS_DENIED_ERROR访问。


连接postgresql

驱动下载:https://jdbc.postgresql.org/download.html


AWT

API文档:https://www.apiref.com/java11-zh/java.desktop/java/awt/package-summary.html
Container文档:https://www.apiref.com/java11-zh/java.desktop/java/awt/Container.html

AWT(Abstract Windowing Toolkit,抽象窗口工具包),是Java提供的用来建立和设置Java图形用户界面的基本工具。
AWT由Java中的java.awt包提供,里面包含了许多可用来建立与平台无关的图形用户界面(GUI)的类,这些类又被称为组件(components)。
由于Java是一种独立于平台的程序设计语言,但GUI却往往是依赖于特定平台的,Java采用了相应的技术使得AWT能提供给应用程序独立于机器平台的接口,这保证了同一程序的GUI在不同机器上运行具有类似的外观(不一定完全一致)。
Swing是Sun公司后期推出的图形用户界面包。它基于AWT,并做出了更多改进。

Container

Container 类是 Component 的子类,其有两个子类:Panel,Window。
Window 可独立于其他 Container 而存在。主要有两个子类:Frame,Dialog。

Container 中组件的位置和大小默认由布局管理器 layout manager 决定。Java主要包含以下几种布局管理器:

Flow Layout:Panel, Applet 的默认布局管理器。
Border Layout:Window, Frame, Dialog 的默认布局管理器。
Grid Layout
Card Layout
GridBag Layout

使用setLayout()改变使用的布局管理器。
使用setLayout(null)可不用管理器,以便使用setLocation(), setSize(), setBounds()自定义数据,但不推荐?可能会使程序变得与平台相关。(然而不自定义根本做不出合适的)

Panel 对象创建后,必须加到 Window 或 Frame 对象中才能成为可见的。

Event

事件类的层次结构:

  1. java.lang.Object
  2. |
  3. +...java.util.EventObject
  4. |
  5. +...java.awt.AWTEvent
  6. |
  7. +...java.awt.event.ActionEvent(鼠标在按钮或文本框键击)
  8. +...
  9. |
  10. +...java.awt.event.WindowEvent(窗口事件)
  11. +...
  12. |
  13. +...java.awt.event.MouseEvent(鼠标事件)

JDK使用委托代理模型(Delegation model)处理事件。
如果一个对象想要响应并处理某个事件Ev,则需先使用addEvListener()注册该事件的Listener。该函数的参数为一个类的实例,该类需继承该事件Listener的接口,即implements EvListener,并实现了处理该事件的方法(方法名取决于事件类型)。
这样当收到/产生一个事件时,会自动提交给响应的Listener进行处理。


常用函数

int到String

  1. int num=100;
  2. String s1=""+num;
  3. String s2 =String.valueOf(num);
  4. String s3 =(new Integer(num)).toString();
  5. String s4 =Integer.toString(i);

int到String

  1. String s="100";
  2. Integer ii =new Integer(s);
  3. int x=ii.intValue();
  4. int y = Integer.parseInt(s);

其它

读入
https://www.runoob.com/java/java-scanner-class..html

输出
使用:import static java.lang.System.out;,用static import导入class的静态方法。
然后System.out.println可写为out.println

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注