@SovietPower
2022-05-08T13:29:50.000000Z
字数 11583
阅读 1122
学习笔记
作业部落链接: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
命令。
安装插件 Extension Pack for Java。
在setting.json
里添加插件设置:
"java.import.gradle.java.home": "F:\\Programs\\Java\\jdk-17.0.2",
"java.configuration.runtimes": [
{
"name": "JavaSE-17",
"path": "F:\\Programs\\Java\\jdk-17.0.2"
},
{
"name": "JavaSE-1.8",
"path": "F:\\Programs\\Java\\jdk1.8.0_321"
}
]
测试
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 进制, 如:
int decimal = 100;
int octal = 0144;
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
default
的位置任意。因为是哈希表直接跳转,所以能不能匹配到元素与default
的位置无关。一般使用的 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
一个对象,此时多个相同数值的对象存在不同的位置。
当对象和数值进行比较时,会进行拆箱比较其数值。
public class A {
public static void main(String[] args)
{
Integer i = new Integer(1);
Integer j = 1;
Integer k = Integer.valueOf(1);
System.out.printf("%b %b %b\n", i == j, i == k, j == k);
Integer a = 128, b = 128;
Integer c = 127, d = 127;
int x = 1, y = 1;
System.out.printf("%d %d %d %d\n", a, b, c, d);
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(c == d);
System.out.println(x == y);
System.out.println(a == 128);
}
}
/*
输出:
false false true
128 128 127 127
false
true
true
true
true
*/
Java 的 String 为一个类,而不是基本数据类型。
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:
public class A {
public static void main(String[] args)
{
String s1 = "abc"; // String 直接创建
String s2 = s1; // 相同引用
String s3 = new String("abc"); // String 对象创建
System.out.printf("%b %b %b\n", s1 == s2, s1 == s3, s2 == s3);
System.out.printf("%b %b %b\n", s1.equals(s2), s1.equals(s3), s2.equals(s3));
}
}
/*
输出:
true false false
true true true
*/
与基本数据类型不同,String 对象保存的值不可修改,只能新建一个对象。
如需修改,使用StringBuffer 和 StringBuilder 类。
使用String.concat()
或+
连接字符串(包括字符粗常量)。
String.format()
可创建格式化字符串(用法与printf
相同,但返回字符串)
字符串常量之间进行+
,会直接计算得出常量结果。值相同的常量只会创建一次,所以它们地址相同。
但对字符串常量使用concat
,或对字符串变量使用+
(即使是与常量),不会直接进行计算,而是会创建 StringBuilder 或 StringBuffer 对象,使用append
连接。这些对象中的每个都有自己的地址。
这两种方式得到的相同字符串,地址也是不同的。
public class HelloWorldA {
public static void main(String[] args)
{
String t1="a"+"b"+"c";
String t2="abc";
System.out.printf("t: %b %b\n", t1==t2, t1.equals(t2));
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.printf("s: %b %b %b\n", s1 == s2, s1 == s3, s2 == s3);
System.out.printf("s: %b\n", s2.equals(s3));
String q1 = "a".concat("b").concat("c");
String q2 = "a"+"b"+"c";
String q3 = "abc";
System.out.printf("q: %b %b %b\n", q1 == q2, q1 == q3, q2 == q3);
System.out.printf("q: %b %b %b\n", q1.equals(q2), q1.equals(q3), q2.equals(q3));
}
}
/*
输出:
t: true true
s: false false false
s: true
q: false false true
q: true true true
*/
常用函数
若要获取单个字符,不能用[]
,需用charAt
或substring
。
String不可迭代(for遍历),所以遍历只能枚举charAt(i)
。
https://www.runoob.com/java/java-stringbuffer.html
使用某个类型[]
创建定长数组。
https://www.runoob.com/java/java-arraylist.html
https://www.liaoxuefeng.com/wiki/1252599548343744/1265112034799552
动态数组。
有两个子类:ArrayList
和LinkedList
。
前者类似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对象赋给参数,所以即使是传递了地址,原有对象也不会因参数改变而改变。
注意,很多对象参数使用=
赋值,并不会改变原有对象,除非用改变自身(而不是返回新的)的相应方法。
检查型异常(Checked Exception)
在Java中所有不是RuntimeException派生的Exception都是检查型异常。当函数中存在可能(?)抛出检查型异常的操作时(如打开文件),该函数的函数声明中必须包含throws
,或必须捕获该异常,否则程序终止。如是前者,则调用该函数的函数必须对该异常进行处理,否则也应在函数后声明throws
。
编译器会检查这类异常,如果在编译时没有处理这些异常(没有throws
也没catch
),则无法通过编译。可以强制开发者在运行前就处理。
处理异常的方式就是两种:throws
或try catch
。
如果异常用catch
没匹配到相应类型的错误,则该异常算作没被捕获,程序终止。
catch
内可以为空,也算捕获并处理了该类型错误(即忽略)。
非检查型异常/运行时异常(Unchecked Exception/Runtime Exception)
编译器不会检查这类异常。这类异常一般可以避免,如除0、数组越界、访问null,所以不强制catch
。
而且一般无法恢复或不可捕获,所以一般让程序直接终止。
使用throw new Exception()
主动抛出任意异常。
try-with-resources
JDK7 之后,Java 新增的 try-with-resource 语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
JDK7 之前所有被打开的系统资源,比如流、文件或者 Socket 连接等,都需要被开发者手动关闭,否则会造成资源泄露将。
try (resource declaration) {
// 使用的资源
} catch (ExceptionType e1) {
// 异常块
}
以上的语法中 try 用于声明和实例化资源,catch 用于处理关闭资源时可能引发的所有异常。
declaration中就要给变量赋值,且之后不能更改。
类不能继承多个类(不能多继承),但可以链式继承(可以多重继承)。
类可以继承多个接口interface
。
使用extends [class]
继承一个类,使用implements [interface1, interface2, ...]
继承多个接口。
super
表示当前对象的父类,可用来访问父类成员。this
表示当前对象。
子类拥有父类的非私有属性和方法。
子类不继承父类的构造器(构造方法或构造函数),但它会调用(隐式或显式)父类的构造器。如果父类的构造器带有参数,则必须在子类构造器中显式地通过super
调用父类的构造器,并传递适当的参数。
如果父类构造器没有参数,则在子类构造器中不需要使用super
调用父类构造器,系统会自动调用父类的无参构造器。
继承提高了类之间的耦合性。耦合度高会造成代码之间的联系紧密,代码独立性差。
所有的类都继承于java.lang.Object
。
final
可修饰变量(类属性、对象属性、局部变量、形参)、方法(类方法、对象方法)和类。
final
声明的类为最终类,不能被继承(但其属性、方法并不一定是final
的)。
final
修饰的方法不能被子类重写。
https://www.runoob.com/java/java-override-overload.html
抽象类abstract class
不能被实例化成对象,其他与一般类相同。抽象类只用来被继承。一个类只能继承一个抽象类。
抽象方法不能被直接调用,是一个必须被子类实现的方法的占位符。抽象方法只有声明,没有函数体,具体需由子类实现。
如果一个类包含抽象方法,那么该类必须是抽象类。但抽象类可以有非抽象方法(与一般类相同)。
任何子类必须重写父类的抽象方法,或声明自身为抽象类。
构造方法,类方法(静态方法)不能声明为抽象方法。
https://blog.csdn.net/qq_42988868/article/details/121633508
下载驱动包: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
)
import java.sql.*;
public class Exercise
{
static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // 驱动名
static final String DB_URL = "jdbc:mysql://localhost:3306/db_name?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; // 数据库 URL
public static void main(String... args)
{
String username = "root";
String password = "111";
Connection conn = null;
Statement stmt = null;
try
{
// 注册 JDBC 驱动
Class.forName(JDBC_DRIVER);
// 打开链接
System.out.println("Connecting");
conn = DriverManager.getConnection(DB_URL, username, password);
// 执行查询
System.out.println("Instancing Statement");
stmt = conn.createStatement();
String sql;
sql = "SELECT id, name FROM test";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next())
{
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.print("ID: " + id);
System.out.println(", name: " + name);
}
// 关闭
rs.close();
stmt.close();
conn.close();
}
catch(SQLException se)
{
// 处理 JDBC 错误
se.printStackTrace();
}
catch(Exception e)
{
// 处理 Class.forName 错误
e.printStackTrace();
}
finally
{
// 关闭资源
try {
if(stmt!=null) stmt.close();
}
catch(SQLException se2) {
// do nothing
}
try {
if(conn!=null) conn.close();
}
catch(SQLException se) {
se.printStackTrace();
}
}
System.out.println("finish!");
}
}
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
访问。
驱动下载:https://jdbc.postgresql.org/download.html
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 类是 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 对象中才能成为可见的。
事件类的层次结构:
java.lang.Object
|
+...java.util.EventObject
|
+...java.awt.AWTEvent
|
+...java.awt.event.ActionEvent(鼠标在按钮或文本框键击)
+...
|
+...java.awt.event.WindowEvent(窗口事件)
+...
|
+...java.awt.event.MouseEvent(鼠标事件)
JDK使用委托代理模型(Delegation model)处理事件。
如果一个对象想要响应并处理某个事件Ev
,则需先使用addEvListener()
注册该事件的Listener。该函数的参数为一个类的实例,该类需继承该事件Listener的接口,即implements EvListener
,并实现了处理该事件的方法(方法名取决于事件类型)。
这样当收到/产生一个事件时,会自动提交给响应的Listener进行处理。
int到String
int num=100;
String s1=""+num;
String s2 =String.valueOf(num);
String s3 =(new Integer(num)).toString();
String s4 =Integer.toString(i);
int到String
String s="100";
Integer ii =new Integer(s);
int x=ii.intValue();
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
。