Java基础学习笔记
强类型语言
要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
数据类型
Java数据类型分为基本类型和引用类型
基本类型有short int long(long类型要在数字后面加个L或l) byte boolean char float(float类型要在数字后面加个F或f)) double
基本数据类型的特点:直接存储在栈中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
int类型
数字前面加个0为八进制数,如010 = 8
数字前面加个0x为十六进制数,如0x10 = 16
float与double类型
float f01 = 231241232f;
float f02 = f01+1;
float f03 = 0.1f;
double f04 = 1.0/10;
System.out.println(f01);
System.out.println(f02);
System.out.println(f01==f02);
System.out.println(f03);
System.out.println(f04);
System.out.println(f03==f04);
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDGu92wV-1611732201214)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210121111613926.png)]
原因:精度缺失
转义字符
- \t制表符
- \n换行
- \b当前位置向前移一格
- \\表示一个\
- \‘表示一个’
- \"表示一个”
- \0表示一个空字符
数据转换
优先级低 -> 高:byte,short,char -> int -> long -> float -> double
优先级低转到高自动转换
优先级高转到低强制转换(可能会内存溢出或有精度问题)
不能对boolean进行转换
数字之间可以用下划线分割,如:1_000 = 1000
idea反编译
指将.java文件编译好的字节流文件反编译成.class文件
java文件的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvj2axNz-1611732201219)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210121211612593.png)]
class文件的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOqhOn8A-1611732201222)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210121211522075.png)]
idea JavaDoc的编写
再类名上一行/**加回车即可编辑JavaDoc
常用信息
@author作者名
@version版本号
@since使用的jdk版本
@param参数名
@return返回值情况
@throws异常抛出情况
前三个用于类注释
后三个用于方法注释
idea生成JavaDoc文档 点击链接
可变参数
基本类型后面加三个点,即可传多个参数,原则上相当于数组
public class test02 {
public static void main(String[] args) {
double max = sort(1.0,4.3,9.0,0.3);
System.out.println(max);
}
public static double sort(double... numbles){
if (numbles.length == 0){
System.out.println("无参数");
}
double max = numbles[0];
for (double numble :numbles){
if (numble>max){
max = numble;
}
}
return max;
}
}
数组的三种初始化方式
-
静态初始化 (不可改变)
int[] a = {1,2,3,4,5};
-
动态初始化 (包含第三种初始化方式默认初始化,默认值为0)
int[] b = new int[10];
数组的注意点
- 数组的长度是确定的,一旦创建,大小就是不可以改变
- 元素可以是基本类型和引用类型
- 数组本身就是对象,Java对象都是在堆中的,因此数组无论保存原始类型还是其他对象类型,对象本身是在堆中的
- 数组的工具类Arrays类,Arrays.toString(数组) 打印数组的每一个元素,Arrays.sort(数组) 对数组排序,Arrays.fill(数组,数) 填充某个数到数组中,Arrays.equals(数组,数组) 两个数组进行比较 ,Arrays.binarySearch(数组,数) 用二分法从一个数组中查找一个数
稀疏数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WdWIqAh7-1611732201226)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210122162002034.png)]
将原来的数组转化为一个新的数组,第一行为数组信息,后面的行都是对每个点的描述
instanceof关键字
instance英文原译为例子,实例
instanceof 是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XGb5MGuD-1611732201228)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123114059532.png)]
如果一个对象 instanceof 本类或者父类返回true
如果一个对象 instanceof 同级其他子类返回false
如果一个对象 instanceof 毫不相关其他类则会报错
transient关键字
transient英文原译为短暂的,暂时的
一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。也可以认为在将持久化的对象反序列化后,被transient修饰的变量将按照普通类成员变量一样被初始化
public class TransientTest implements Serializable{
private static final long serialVersionUID = -2544565384603260469L;
private transient int i = 10;
public static void main(String[] args) throws IOException, ClassNotFoundException {
TransientTest transientTest01 = new TransientTest();
transientTest01.i = 11;
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\Administrator\\test.txt")));
out.writeObject(transientTest01);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\Administrator\\test.txt")));
TransientTest transientTest02 = (TransientTest) in.readObject();
in.close();
System.out.println(transientTest02.i);
}
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3GtaNSy9-1611732201229)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123115416385.png)]
去掉transient关键字运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UiK3r58X-1611732201231)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123115457234.png)]
如果一个对象 instanceof 毫不相关其他类则会报错
volatile关键字
volatile英文原译为易变的,易挥发的
Object类
- hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable
String s01 = "A";
String s02 = "A";
String s03 = new String("A");
String s04 = new String("A");
System.out.println(s01.hashCode());
System.out.println(s02.hashCode());
System.out.println(s03.hashCode());
System.out.println(s04.hashCode());
//“==” 是一个比较运算符号,既可以比较基本数据类型,也可以比较引用数据类型,基本数据类型比较的是值,引用数据类型比较的是地址值
//equals()是一个方法,只能比较引用数据类型,所有的对象都会继承 Object 类中的方法,没有重写 Object 类中的 equals 方法,equals方法和==号比较引用数据类型无区别,重写后的equals方法比较的是对象中的属性,String类已经重写了equlas()方法
System.out.println(s01==s02);
System.out.println(s01.equals(s02));
System.out.println(s01==s03);
System.out.println(s01.equals(s03));
System.out.println(s03==s04);
System.out.println(s03.equals(s04));
/*运行结果:
65
65
65
65
true
true
false
true
false
true
*/
以HashSet为例:
Set<Product> hashset = new HashSet<>();
Product product01 = new Product("1",1,1);
Product product02 = new Product("1",1,1);
System.out.println("product01.equals(product02):"+product01.equals(product02));
System.out.println("product01.hashCode():"+product01.hashCode());
System.out.println("product02.hashCode():"+product02.hashCode());
hashset.add(product01);
hashset.add(product02);
Iterator iterator = hashset.iterator();
while (iterator.hasNext()){
Product product = (Product) iterator.next();
System.out.println(product);
}
/*运行结果
product01.equals(product02):true
product01.hashCode():76912
product02.hashCode():76912
Product{name='1', price=1, numble=1}
*/
需要重写Product类的equals()和hasCode()方法(可以用Alt+Enter自动重写这两个方法)
// @Override
// public boolean equals(Object obj) {
// return super.equals(obj);
// }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return price == product.price &&
numble == product.numble &&
Objects.equals(name, product.name);
}
// @Override
// public int hashCode() {
// return super.hashCode();
// }
@Override
public int hashCode() {
return Objects.hash(name, price, numble);
}
HashMap向里面put一个键值对时先根据键的equals()和hasCode()方法比较是否有一样的键,如果没有则添加,如果有则更新为新的键值对的值
Map<Product,Integer> hashmap = new HashMap<>();
hashmap.put(product01,1);
System.out.println(hashmap.get(product01));
System.out.println(hashmap.get(product02));
hashmap.put(product02,2);
System.out.println(hashmap.get(product01));
System.out.println(hashmap.get(product02));
/*没有重写这两个方法的测试结果:
1
null
1
2
重写这个两个方法的测试结果:
1
1
2
2
*/
- getClass方法获取对象的真实类的全名称
System.out.println("product01.getClass():"+product01.getClass());
//运行结果:product01.getClass():class com.study.Product
- clone方法
clone()方法实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:
① 实现Cloneable接口,这是一个标记接口,自身没有方法。
② 覆盖clone()方法,可见性提升为public。
如下:
class Product implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Product product03 = (Product) product01.clone();
clone是浅拷贝,即被复制对象的所有值属性都含有与原来对象的相同,而所有的对象引用属性仍然指向原来的对象,如下:
Product product03 = (Product) product01.clone();
System.out.println(product03);
Order order01 = new Order(1, product01);
Order order02 = (Order) order01.clone();
order01.getProduct().setName("2");
System.out.println(order01);
System.out.println(order02);
/*测试结果为:
Order{orderID=1, product=Product{name='2', price=1, numble=1}}
Order{orderID=1, product=Product{name='2', price=1, numble=1}}
*/
/*修改代码为:
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Product product = ((Order) obj).getProduct();
((Order) obj).setProduct((Product) product.clone());
return obj;
}
*/
/*测试结果为:
Order{orderID=1, product=Product{name='1', price=1, numble=1}}
Order{orderID=1, product=Product{name='2', price=1, numble=1}}
*/
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AmVELEdY-1611732319107)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123173524407.png)]
Math类
- sqrt() 平方根
- cbrt() 立方根
- pow() 平方
- max() 求最大值
- min() 求最小值
- abs() 求绝对值
- ceil() 向上取整
- floor() 向下取整
- round() 四舍五入返回int
- rint() 四舍五入返回double
- random() 输出[0,1)间的随机数
Random类
- nextInt(3) 返回一个[0,3)int类型的数
- nextDouble() 返回一个[0,1)double类型的数
- nextBoolean() 返回一个true或false
File类
- getName() 获取文件名字
- getPath() 获取文件路径
- isFile() 判断是否为文件
- isDirectory() 判断是否为路径
- canRead() 判断是否可读
- canWrite() 判断是否可写
- length() 返回文件大小(单位为字节)
- isHidden() 判断文件是否隐藏
- exists() 判断文件是否存在
- listFiles() 返回目录下所有文件,如果是文件则为空
- delete() 删除该文件
- createNewFile() 根据抽象路径创建一个新的空文件,当抽象路径制定的文件不存在时,创建成功返回true,当抽象路径制定的文件存在时,创建失败返回false
- mkdir() 创建此抽象路径名指定的目录,创建成功返回true,创建失败返回false
- mkdirs() 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录
- renameTo() 如果路径相同就是改名并删除内容,如果路径不同就是改名并剪切到该路径下,传入参数为File类对象
包装类
Character的方法:
- toLowerCase() 将字符变为小写
- toUpperCase() 将字符变为小写
- isLowerCase() 判断字符是否为小写
- isUpperCase() 判断字符是否为大写
- isDigit() 判断字符是否为数字
- isWhiteSpace() 判断字符是否为空格
Integer的方法:
- toBinaryString() 转换为二进制字符串
- toBinaryString() 转换为二进制字符串
- valueOf() 将字符串转换为整数,同parseInt()
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8vJ7Al2-1611732319116)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123210455372.png)]
运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uR1uHVY-1611732319121)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123210608862.png)]
原理解释:java针对-128-127之间的数据做了一个数据缓冲池。
如果数据是该范围内的,每次并不创建新的空间。
如果数据是该范围内的,就new一个空间
源码:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCHTcZFj-1611732319123)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210123211043822.png)]
String的方法:
- length() 返回字符串的长度
- concat() 拼接字符串
- charAt() 索引字符串中第几个字符
- indexOf() 返回指定字符或字符串的第一个字符的索引
- toLowerCase() 将字符串中大写字符变为小写
- toUpperCase() 将字符串中小写字符变为大写
- toCharArray() 将字符串转换为字符
- contains() 判断字符串中是否包含某个字符串
- startsWith() 判断字符串是否以某个字符串开头
- endsWith() 判断字符串是否以某个字符串结尾
- getBytes() 将字符串编码为byte序列,返回一个新的byte数组中
- matches() 判断字符串是否匹配给定的正则表达式
- replace() 将字符串的指定字符换为新字符并返回该字符串
- replaceAll() 将字符串的指定字符串换为新字符串并返回该字符串
- split() 根据给定正则表达式的匹配拆分此字符串,并返回一个字符串数组
- substring() 返回字符串的一个子串
- trim() 返回一个去前后空格的字符串
- equals() 字符串比较相等
- equalsIgnoreCase() 字符串比较相等忽略大小写
StringBuilder与StringBuffer类
- append() 在字符串后面追加内容
- length() 返回字符串的长度
- setCharAt() 替换指定位置的一个字符串
- insert() 在指定位置插入字符
- delete() 删除指定区间字符串
- charAt() 索引字符串中第几个字符
- indexOf() 返回指定字符串的第一个字符的索引
- reverse() 返回字符序列倒序的字符串
String,StringBuilde和StringBuffer特性比较:
速度比较:String < StringBuffer < StringBuilder
原因:
- String是不可变的对象
- StringBuffer是可变对象
- StringBuilder是可变对象
(1)String本身就是一个对象,因为String不可变对象,所以,每次遍历对字符串做拼接操作,都会重新创建一个对象。
(2)StringBuffer和StringBuilder只需要创建一个StringBuffer或StringBuilder对象,然后用append拼接字符串,就算拼接一亿次,仍然只有一个对象。
(3)String遍历代码:一开始定义一个String常量(创建一个String对象), 再开始遍历;
(4)StringBuffer代码:一开始定义一个String常量(创建一个String对象)和一个创建StringBuffer对象,再开始遍历;
(5)StringBuiler代码:一开始定义一个String常量(创建一个String对象)和一个创建StringBuiler对象,再开始遍历;
- StringBuffer是线程安全的
- StringBuilder是非线程安全的, 这也是速度比StringBuffer快的原因
使用场景:
- 如果要操作少量的数据用 String
- 单线程操作字符串缓冲区 下操作大量数据 StringBuilder
- 多线程操作字符串缓冲区 下操作大量数据 StringBuffer
时间类
Date类(方法快要过期不推荐使用)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-deWQiNgQ-1611732319124)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210124160231115.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MpAJTm0F-1611732319125)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210124155756991.png)]
SimpleDateFormat类
format() 传入一个Date类型转换其格式
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(date));
df = new SimpleDateFormat("现在是北京时间yyyy年MM月dd日 HH:mm:ss:SS,今天是E,新年的第D天,第w个星期,现在的时间是(a)hh:mm:ss");
System.out.println(df.format(date));
/*输出结果:
2021-01-24 16:15:29
现在是北京时间2021年01月24日 16:15:29:596,今天是星期日,新年的第24天,第5个星期,现在的时间是(下午)04:15:29
*/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHsIk7G7-1611732319127)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210124161706563.png)]
Calendar类
Calendar now = Calendar.getInstance();
Calendar now01 = new GregorianCalendar(); //无参构造
Calendar before = new GregorianCalendar(2021,0,23,16,54,32); //有参构造
System.out.println(now.get(Calendar.YEAR));
System.out.println(now.get(Calendar.MONTH)+1);
System.out.println(now.get(Calendar.DATE));
System.out.println(now.get(Calendar.DAY_OF_WEEK)); //1表示星期天以此类推
System.out.println(now.get(Calendar.HOUR_OF_DAY));
System.out.println(now.get(Calendar.MINUTE));
System.out.println(now.get(Calendar.SECOND));
if(now.get(Calendar.AM_PM) == 0){
System.out.println("上午");
}else {
System.out.println("下午");
}
System.out.println(before.get(Calendar.SECOND));
before.set(Calendar.SECOND,45); //也可通过该方法设置其他信息
System.out.println(before.get(Calendar.SECOND));
before.add(Calendar.SECOND,-10); //也可通过该方法设置其他信息
System.out.println(before.get(Calendar.SECOND));
System.out.println(before.before(now01)); //也可以通过after判断在之后
// Calendar类型转Date类型
Date nowTrans = now.getTime();
System.out.println(df.format(nowTrans));
// Date类型转Calendar类型
Calendar calendar = new GregorianCalendar();
calendar.setTime(nowTrans);
/*输出结果:
2021
1
24
1
16
44
9
下午
32
45
35
true
现在是北京时间2021年01月24日 16:44:09:628,今天是星期日,新年的第24天,第5个星期,现在的时间是(下午)04:44:09
*/
java正则表达式
在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \ 代表其他语言中的一个 \,这也就是为什么表示一位数字的正则表达式是 \d,而表示一个普通的反斜杠是 \\。
- . 匹配一个所有字符
- [0-9] 代表匹配0-9的一个字符
- [0-9]* 后面加一个*代表匹配0-9的n个字符
- [a-zA-Z]* 匹配n个大小写字母
- \\d 代表匹配0-9的一个字符
- \\d{n} 代表匹配0-9的n个字符
- \\d{n,} 代表匹配0-9的至少n个字符
- \\d{n,m} 代表匹配0-9的n到m个字符
- + 用于匹配一个到n个字符,相当于{1,}
- ? 用于匹配零到一个字符,相当于{0,1}
- *用于匹配零到n个字符,相当于{0,}
- [abc] 用于匹配abc中任何一个字符
- [^abc] 用于匹配除abc以外任何一个字符
- (-)?\d+(.\d{1,2})? 用于匹配带1-2位小数的正数或负数
- ^ [0-9]+(.[0-9]{1,3})?$ 于匹配带1~3位小数的正实数
- \\w 匹配任何字类字符,包括下划线,与"[A-Za-z0-9_]"等效
- [a-zA-Z]\\w{5,17} 用于匹配密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)
s = "999";
System.out.println(s.matches("..."));
s = "1";
System.out.println(s.matches("[0-9]"));
s = "12345";
System.out.println(s.matches("[0-9]*"));
s = "abcdEFG";
System.out.println(s.matches("[a-zA-Z]*"));
s = "1";
System.out.println(s.matches("\\d"));
s = "123";
System.out.println(s.matches("\\d{3}"));
s = "1234";
System.out.println(s.matches("\\d{5,}"));
s = "2134";
System.out.println(s.matches("\\d{1,4}"));
s = "1j";
System.out.println(s.matches("\\d+j"));
s = "1j32";
System.out.println(s.matches("\\d?j32"));
s = "32";
System.out.println(s.matches("\\d*32"));
s = "abc";
System.out.println(s.matches("[abc]*"));
s = "efg";
System.out.println(s.matches("[^abc]*"));
s = "-1.30";
System.out.println(s.matches("(-)?\\d+(.[0-9]{1,2})?"));
s = "321.3";
System.out.println(s.matches("^[0-9]+(.[0-9]{1,3})?$"));
s = "_";
System.out.println(s.matches("\\w"));
s = "f321csf_2er";
System.out.println(s.matches("[a-zA-Z]\\w{5,17}"));
/*运行结果:
true
true
true
true
true
true
false
true
true
true
true
true
true
true
true
true
true
*/
matches() 和 lookingAt() 方法都用来尝试匹配一个输入序列模式。不同的是 matches() 要求整个序列都匹配,而 lookingAt() 不要求,lookingAt() 方法虽然不需要整句都匹配,但是需要从第一个字符开始匹配
Pattern pattern = Pattern.compile("ljy");
Matcher matcher = pattern.matcher("ljy123");
System.out.println(Pattern.compile("...").matcher("fd_").matches());
System.out.println(matcher.matches());
System.out.println(matcher.lookingAt());
/*运行结果
true
false
true
*/