本文内容的学习网站:http://how2j.cn/
1、创建 Java 项目
File -> New -> Other -> Java -> Java Project
2、常用快捷键
主方法:main + alt + / 输出:syso + alt + / for语句:for + alt + / try语句:try + alt + / 格式化:ctrl + shift + f
注释:ctrl + shift + c 引包去包:ctrl + shift + o
3、八种基本数据类型
整型(4种):byte,short,int,long 浮点型(2种):float,double 字符型(1种):char 布尔型(1种):boolean
4、操作符
byte a = 1; byte b = 1; a + b -> int类型
& 和 | 两边的表达式都会执行,&& 和 || 如果左边表达式的结果可以确定总结果,右边的表达式不会执行
>>>无符号右移,负数会变成正数
控制台输入:Scanner s = new Scanner(System.in);
Math.random() 会得到一个0-1之间的随机浮点数
5、数组
package com.aroma.review;
import java.util.Arrays;
public class TestArray {
public static void main(String[] args) {
int[] a = new int[3]; //创建数组
int[] b = {1,2,3}; //创建并初始化
//增强型for循环只取值,不能改值
for(int i : b) {
System.out.println(i);
}
//数组的工具类Arrays
//复制数组
int[] b2 = Arrays.copyOfRange(b, 0, 3);
//转为字符串
System.out.println(Arrays.toString(b2));
//排序
a[0] = 2; a[1] = 1; a[2] = 3;
Arrays.sort(a);
System.out.println(Arrays.toString(a));
//搜索,使用binarySearch必须先使用sort排序
System.out.println(Arrays.binarySearch(a, 2));
//比较
System.out.println(Arrays.equals(a, b));
}
}
运行结果:
1
2
3
[1, 2, 3]
[1, 2, 3]
1
true
6、类,对象和属性
实例化一个对象的时候,必然调用构造方法
Hero h = new Hero();的意思为:引用 h 指向一个 Hero 对象(=表示指向,不是赋值)
static 修饰的方法叫做类方法或静态方法,可以直接访问,不需要建立对象
static 修饰的属性叫做类属性或静态属性,所有的对象共享一个值
单例模式
package com.aroma.review;
public class Singleton {
// 类属性,用于指向一个实例化对象
private static final Singleton singleton = new Singleton();
// 私有化构造方法,外部无法进行实例化
private Singleton() {
}
// get方法返回静态属性
private static Singleton getSingleton() {
return singleton;
}
}
7、四种访问修饰符
private:私有的,子类不能继承,其它类也不能访问
package/friendly/default:默认的,同包子类能继承,同包非子类能访问,异包子类不能继承,异包非子类不能访问
protected:受保护的,同包子类能继承,同包非子类能访问,异包子类能继承,异包非子类不能访问
public:公开的,所有类都能访问
8、接口和继承
Java 不允许多继承,但可以实现多个接口,实现某个接口,就必须重写该接口中的方法,接口可以提供默认方法
多态: 同个类型,同个方法,呈现出不同的状态
this 代表当前对象,super 可以调用父类的方法和属性
Object 类是所有类的父类,声明一个类时,默认继承了 Object 类
final 修饰的类不能被继承,final 修饰的方法不能被重写,final 修饰的基本类型变量只有一次赋值的机会
final 修饰的引用只有一次指向对象的机会
抽象类不能够直接实例化,抽象方法没有实现体,抽象类可以没有抽象方法
接口中声明的属性只能是 public final static 的
非静态内部类的实例化必须存在一个外部类对象,匿名类是在声明一个类的同时实例化,本地类可以理解为有名字的匿名类
package com.aroma.review;
public class Hero extends Object {
public String name;
public void attack() {
}
// 构造方法
public Hero() {
}
public Hero(String name) {
this.name = name;
}
// 非静态内部类
class Score {
int kill;
public void legendary() {
if (kill >= 8)
System.out.println(name + " is legendary!");
}
}
// 类方法
public static void victory() {
System.out.println("Victory!");
}
// 静态内部类
static class Crystal {
int hp;
public void win() {
if (hp == 0)
Hero.victory();
}
}
// 主函数
public static void main(String[] args) {
Hero garen = new Hero("Garen");
Score score = garen.new Score();
score.kill = 9;
score.legendary();
Hero.Crystal crystal = new Hero.Crystal();
crystal.hp = 0;
crystal.win();
// 匿名类
Hero h = new Hero() {
public void attack() {
System.out.println("Attack!");
}
};
h.attack();
// 本地类
class newHero extends Hero {
public void attack() {
System.out.println(name + " attack!");
}
}
newHero ahri = new newHero();
ahri.name = "Ahri";
ahri.attack();
}
}
运行结果:
Garen is legendary!
Victory!
Attack!
Ahri attack!
9、数字与字符串
不调用构造方法,通过 = 自动把基本类型转换为类类型叫做装箱
不调用 Integer 的 intValue 方法,通过 = 自动转换成 int 类型叫做拆箱
StringBuffer 是可变长的字符串
package com.aroma.review;
public class Test {
public static void main(String[] args) {
// 数字转字符串
int i = 1;
String s = String.valueOf(i);
// 字符串转数字
String s2 = "2";
int i2 = Integer.parseInt(s2);
// 四舍五入
float f = 1.5f;
System.out.println(Math.round(f));
// 格式化输出
String str = "%s + %d %n";
System.out.printf(str, s, i2);
//获取字符
System.out.println(str.charAt(3));
//获取字符数组
System.out.println(str.toCharArray());
//截取字符串
System.out.println(str.substring(3, 6));
//根据str创建一个StringBuffer对象
StringBuffer str2 = new StringBuffer(str);
//尾部添加
str2.append(" 123");
System.out.println(str2);
//删除
str2.delete(10, 14);
System.out.println(str2);
//插入
str2.insert(3, "123 ");
System.out.println(str2);
}
}
运行结果:
2
1 + 2
+
%s + %d %n
+ %
%s + %d %n 123
%s + %d %n
%s 123 + %d %n
10、日期
日期格式化类 SimpleDateFormat
package com.aroma.review;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDate {
public static void main(String[] args) {
//日期转字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(new Date());
System.out.println(str);
//字符串转日期
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str2 = "2019-10-10 11:30:59";
try {
System.out.println(sdf2.parse(str2).toString());
} catch (ParseException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
运行结果:
2019-10-10 11:31:00
Thu Oct 10 11:30:59 CST 2019
11、异常处理
异常分为三种:可查异常,运行时异常和错误,后两者统称非可查异常
可查异常是必须处理的异常,否则编译器不通过,其它两种异常不要求强制捕获
throw 通常在方法体内,执行 throw 一定是抛出了某个异常
throws 在方法声明上,表示可能出现异常,不一定会发生异常
package com.aroma.review;
public class Hero {
public String name;
protected int hp;
// 构造方法
public Hero() {
}
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
// 自定义异常
@SuppressWarnings("serial")
class IsDeadException extends Exception {
public IsDeadException(String name) {
super(name);
}
}
// 抛出异常
public void attack(Hero h) throws IsDeadException {
if (h.hp == 0)
throw new IsDeadException(h.name + " is dead.");
}
// 主函数
public static void main(String[] args) {
Hero garen = new Hero("Garen", 100);
Hero ahri = new Hero("Ahri", 0);
try {
garen.attack(ahri);
} catch (IsDeadException e) {
// TODO: handle exception
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
运行结果:
Ahri is dead.
com.aroma.review.Hero$IsDeadException: Ahri is dead.
at com.aroma.review.Hero.attack(Hero.java:29)
at com.aroma.review.Hero.main(Hero.java:39)
12、I/O流
ASCII 码及对应十六进制数:0-9 对应 30-39,A-Z 对应 41-5A,a-z 对应 61-7A
InputStream 字节输入流,OutputStream 字节输出流,Reader 字符输入流,Writer 字符输出流
BufferedReader 缓存字符输入流,可以一次读取一行数据,缓存字符输出流 PrintWriter,可以一次写出一行数据
数据输入流 DataInputStream,数据输出流 DataOutputStream
把流定义在 try() 里,try catch 或者 finally 结束时会自动关闭
一个对象以流的形式进行传输,叫做序列化,该对象所对应的类,必须是实现 Serializable 接口
package com.aroma.review;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
public class TestStream {
public static void main(String[] args) {
//需要先在D盘创建test.txt,内容为ABC
File f = new File("d:/test.txt");
try(FileInputStream fis = new FileInputStream(f)) {
//字节数组
byte[] content = new byte[(int) f.length()];
//字节流读取文件内容
fis.read(content);
//循环输出
for(byte b : content) {
System.out.println(b);
}
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
try(FileReader fr = new FileReader(f)) {
//字符数组
char[] content = new char[(int)f.length()];
//字符流读取文件内容
fr.read(content);
//循环输出
for(char c : content)
System.out.println(c);
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
//不需要先在D盘创建test2.txt,会自动创建
File f2 = new File("d:/test2.txt");
try(FileOutputStream fos = new FileOutputStream(f2)) {
//要写入文件的内容
byte[] data = {68, 69};
//写入
fos.write(data);
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
//不需要先在D盘创建test3.txt,会自动创建
File f3 = new File("d:/test3.txt");
try(FileWriter fw = new FileWriter(f3)) {
//要写入的内容
String data = "DE";
//写入
fw.write(data.toCharArray());
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
/*需要先在D盘创建test4.txt,内容为
*Life is dear
*Love is dearer
*Both can be given up for freedom
*/
File f4 = new File("d:/test4.txt");
try( //缓存流必须建立在一个存在的流的基础上
FileReader fr = new FileReader(f4);
BufferedReader br = new BufferedReader(fr);
) {
while(true) {
String line = br.readLine();
if(line == null)
break;
System.out.println(line);
}
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
//不需要先在D盘创建test5.txt,会自动创建
File f5 = new File("d:/test5.txt");
try( //缓存流必须建立在一个存在的流的基础上
FileWriter fw = new FileWriter(f5);
PrintWriter pw = new PrintWriter(fw);
) {
pw.println("Life is dear");
pw.println("Love is dearer");
pw.println("Both can be given up for freedom");
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
Hero h = new Hero("Garen", 100);
//需要先在D盘创建test6.txt用于保存该对象
File f6 = new File("d:/test6.txt");
try(
//创建对象输出流
FileOutputStream fos = new FileOutputStream(f6);
ObjectOutputStream oos =new ObjectOutputStream(fos);
//创建对象输入流
FileInputStream fis = new FileInputStream(f6);
ObjectInputStream ois =new ObjectInputStream(fis);
) {
oos.writeObject(h);
Hero h2 = (Hero) ois.readObject();
System.out.println(h2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.aroma.review;
import java.io.Serializable;
public class Hero implements Serializable {
//类当前版本
private static final long serialVersionUID = 1L;
public String name;
public int hp;
//构造方法
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
//重写toString方法
@Override
public String toString() {
return "[name=" + name + ", hp=" + hp + "]";
}
}
运行结果:
65
66
67
A
B
C
Life is dear
Love is dearer
Both can be given up for freedom
[name=Garen, hp=100]
13、集合框架
容器类 ArrayList 实现了List接口,容量会自动增长
指定了泛型的容器,只能存放指定类型的元素以及其子类
LinkedList 实现了 List 接口,Queue 接口和双向链表结构 Deque
ArrayList 是顺序结构,增删慢定位快,LinkedList 是链表结构,增删快定位慢
HashMap 储存数据的方式是键值对,对于 HashMap,key 是唯一的
HashMap 可以存放 null,线程不安全,Hashtable 不能存放 null,线程安全
package com.aroma.review;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class TestList {
public static void main(String[] args) {
List<Hero> list = new ArrayList<Hero>();
//增加
for (int i = 0; i < 5; i++) {
list.add(new Hero("Hero " + i));
}
list.add(3, new Hero("newHero"));
System.out.println(list);
//删除
list.remove(3);
//遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Queue<Hero> queue = new LinkedList<Hero>();
//队列,先进先出
for (int i = 0; i < 5; i++) {
queue.offer(new Hero("Hero " + i));
}
System.out.println(queue);
//栈,后进先出
class MyStack<T> {
//方便在头尾插入删除数据
LinkedList<T> list = new LinkedList<T>();
//进栈
public void push(T t) {
list.addLast(t);
}
//出栈
public T pop() {
return list.removeLast();
}
}
MyStack<Hero> stack = new MyStack<Hero>();
for (int i = 0; i < 5; i++) {
stack.push(new Hero("Hero " + i));
}
for (int i = 0; i < 5; i++) {
System.out.println(stack.pop());
}
//取出与存入的数据顺序是不一致的
HashMap<String,Hero> map = new HashMap<String,Hero>();
for (int i = 0; i < 5; i++) {
Hero h = new Hero("Hero " + i);
map.put(h.name, h);
}
System.out.println(map);
}
}
package com.aroma.review;
public class Hero {
public String name;
//构造方法
public Hero(String name) {
this.name = name;
}
//重写toString方法
@Override
public String toString() {
return name;
}
}
运行结果:
[Hero 0, Hero 1, Hero 2, newHero, Hero 3, Hero 4]
Hero 0
Hero 1
Hero 2
Hero 3
Hero 4
[Hero 0, Hero 1, Hero 2, Hero 3, Hero 4]
Hero 4
Hero 3
Hero 2
Hero 1
Hero 0
{Hero 1=Hero 1, Hero 0=Hero 0, Hero 3=Hero 3, Hero 2=Hero 2, Hero 4=Hero 4}
14、Lambda
Lambda其实就是匿名方法,是一种把方法作为参数传递的编程思想
管道是一系列的聚合操作,分为管道源,中间操作和结束操作
package com.aroma.review;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TestLambda {
public static void main(String[] args) {
// 初始化
Random r = new Random();
List<Hero> list = new ArrayList<Hero>();
for (int i = 0; i < 5; i++) {
list.add(new Hero("Hero " + i, r.nextInt(1000), r.nextInt(100)));
}
// 使用匿名类
Check check = new Check() {
public boolean test(Hero h) {
return h.hp > 100 && h.damage < 50;
}
};
System.out.println("匿名类:");
filter(list, check);
// 使用Lambda
System.out.println("Lambda:");
filter(list, h -> h.hp > 100 && h.damage < 50);
// 使用静态方法
System.out.println("静态方法:");
filter(list, TestLambda::test);
// 使用对象方法
System.out.println("对象方法:");
filter(list, Hero::test);
// 使用聚合操作
System.out.println("聚合操作:");
list
.stream()
.filter(h -> h.hp > 100 && h.damage < 50)
.forEach(h -> System.out.println(h));
}
// 静态方法
private static void filter(List<Hero> list, Check check) {
for (Hero h : list) {
if (check.test(h))
System.out.println(h);
}
}
public static boolean test(Hero h) {
return h.hp > 100 && h.damage < 50;
}
//接口
interface Check {
public boolean test(Hero h);
}
}
package com.aroma.review;
public class Hero {
public String name;
public float hp;
public int damage;
//构造方法
public Hero(){
}
public Hero(String name,float hp, int damage) {
this.name =name;
this.hp = hp;
this.damage = damage;
}
public boolean test(){
return this.hp>100 && this.damage<50;
}
//重写toString方法
@Override
public String toString() {
return "[name=" + name + ", hp=" + hp + ", damage=" + damage + "]";
}
}
运行结果:
匿名类:
[name=Hero 1, hp=132.0, damage=36]
[name=Hero 2, hp=997.0, damage=4]
Lambda:
[name=Hero 1, hp=132.0, damage=36]
[name=Hero 2, hp=997.0, damage=4]
静态方法:
[name=Hero 1, hp=132.0, damage=36]
[name=Hero 2, hp=997.0, damage=4]
对象方法:
[name=Hero 1, hp=132.0, damage=36]
[name=Hero 2, hp=997.0, damage=4]
聚合操作:
[name=Hero 1, hp=132.0, damage=36]
[name=Hero 2, hp=997.0, damage=4]
15、多线程
创建多线程有3种方式,分别是继承线程类,实现Runnable接口和匿名类
如果一个类,其方法都是有 synchronized 修饰的,那么该类就叫做线程安全的类
线程池的思路和生产者消费者模型是很接近的
16、JDBC
JDBC(Java DataBase Connection)是通过Java访问数据库
导入mysql-connector-java-5.1.30.jar包:项目右键Properties -> Java Build Path -> Libraries -> Add External JARs...
jar包下载地址:https://mvnrepository.com/
Connection 用于与数据库建立连接,Statement用于执行sql语句
PreparedStatement有预编译机制,性能比Statement更快,可防止sql注入式攻击
ORM(Object Relationship Database Mapping)对象和关系数据库的映射
DAO(Data Access Object)数据访问对象
package com.aroma.review;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
// 初始化驱动
try {
// 忘记导包会抛出ClassNotFoundException
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 数据库必须先创建hero表
String sql = "insert into hero values(null,?,?,?)";
try (
// 数据库的ip,端口号,名称,编码方式,账号和密码
Connection c = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/aroma?&characterEncoding=utf8","root","root");
// Statement用于执行sql语句
Statement s = c.createStatement();
// PreparedStatement需要根据sql语句创建
PreparedStatement ps = c.prepareStatement(sql);) {
// 插入,每次都要编译
for (int i = 0; i < 5; i++) {
String sql2 = "insert into hero values(null," + "'Ahri'" + "," + 99.0f + "," + 40 + ")";
s.execute(sql2);
}
// 插入,预编译,响应更快
for (int i = 0; i < 5; i++) {
ps.setString(1, "Garen");
ps.setFloat(2, 100.0f);
ps.setInt(3, 50);
ps.execute();
}
// 删除
String sql3 = "delete from hero where id = 1";
s.execute(sql3);
// 修改
String sql4 = "update hero set name = 'Annie' where id = 2";
s.execute(sql4);
// 遍历
String sql5 = "select * from hero";
ResultSet rs = s.executeQuery(sql5);
while (rs.next()) {
System.out.printf("%d\t %s\t %f\t %d%n", rs.getInt(1), rs.getString(2), rs.getFloat(3), rs.getInt(4));
}
// 总记录数
String sql6 = "select count(*) from hero";
ResultSet rs2 = s.executeQuery(sql6);
int count = 0;
while (rs2.next()) {
count = rs2.getInt(1);
}
System.out.println("总共" + count + "条数据");
// 获取元数据
DatabaseMetaData dbmd = (DatabaseMetaData) c.getMetaData();
System.out.println("产品名称:" + dbmd.getDatabaseProductName());
System.out.println("产品版本:" + dbmd.getDatabaseProductVersion());
System.out.println("分隔符:" + dbmd.getCatalogSeparator());
System.out.println("驱动版本:" + dbmd.getDriverVersion());
ResultSet rs3 = dbmd.getCatalogs();
while(rs3.next()) {
System.out.println("数据库名称:" + rs3.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
2 Annie 99.000000 40
3 Ahri 99.000000 40
4 Ahri 99.000000 40
5 Ahri 99.000000 40
6 Garen 100.000000 50
7 Garen 100.000000 50
8 Garen 100.000000 50
9 Garen 100.000000 50
10 Garen 100.000000 50
总共9条数据
产品名称:MySQL
产品版本:5.7.27
分隔符:.
驱动版本:mysql-connector-java-5.1.30 ( Revision:${svn.Revision} )
数据库名称:information_schema
数据库名称:aroma
数据库名称:mysql