JavaSE学习笔记
IDEA快捷键
查找类型 ctrl+n
查找资源 双击shift
方法重写 ctrl+O
快速导包 alt+enter
放大编码区 ctrl+shift+F12
错误改正: alt+Enter
关键字
this
this是一个引用、变量,指向了对象本身,this存储在JVM堆内存java对象内部
this可以出现在“实例方法”中,指向当前正在执行这个动作的对象
带有static的方法没有当前对象,因为带有static的方法是通过类名访问的,包括main方法 所以不能直接访问实例变量和实例方法
不能省略的this
用来区分局部变量和实例变量时不能省(变量和原有属性同名)
独特的this方法 构造方法中使用
this(构造参数)在构造函数调用现有的构造函数,且不会生成新的对象 且必须是在该构造方法中第一行
关于this的所有相关函数
public class TestThis {
int i=10;
public static void doSome(){
System.out.println("do some");
}
public void doOther(){
System.out.println("do Other");
}
//静态方法 没有上下文对象 没有this
public static void method1() {
TestThis.doSome();
doSome();
TestThis t=new TestThis();
t.doOther();
System.out.println(t.i);
}
public void method2() {
TestThis.doSome();
// ?? 不需要对象,自动使用类名调用
doSome();
this.doOther();
doOther();
System.out.println(this.i);
System.out.println(i);
}
//静态方法 没有上下文对象 没有this
public static void main(String[] args) {
TestThis.method1();
method1();
TestThis t=new TestThis();
t.method2();
}
}
super
this与super作为构造方法不能共存
super()只能出现在构造方法第一行,通过当前构造方法掉用父类的构造方法 目的:创建子类对象时,先初始化父类特征
父类和子类中有同名但不同内容的属性内容时不能省略
使用情况
子类通过调用父类构造方法来对父类私有属性进行修改
static
类中统一的属性可以通过static固定,不需要在每个对象中重复生成。
此类静态对象在类加载时就初始化,存储在方法区中
static修饰的元素都可以通过"类名."进行访问
工具类方法一般写作静态 方便调用
Final
final所修饰的不同效果
static final 修饰的变量称为常量, 与静态变量一样,存储在方法区中,在类加载时初始化,但常量不能改变,要求大写 单词间用下划线隔开 且常量一般公开
类:无法被继承
方法:无法被覆盖
变量:无法重新赋值
实例变量:必须在声明时手动赋值且无法修改
引用:一旦赋值不能赋新值 但是所指向对象的属性可以修改 无法被垃圾回收器回收 当整个方法结束才会被回收
package
包机制 包名要全小写
第一章(java的加载与执行)
java的加载与执行
程序阶段:编译+运行
运行阶段:java.exe启动java虚拟机(JVM),JVM启动类加载器ClassLoader,ClassLoader找到对应的class文件并装载到JVM中
public class和class
public class的名字要和源文件名相同,只能有一个
class可以有多个 每个class都能有一个main方法
加载器
JDK带有三个类加载器:启动类加载器 扩展类加载器 应用类加载器
第二章(基础知识)
数据类型
基本数据类型(字节):byte 1,short 2,int 4,long 8 float 4,double 8 boolean 1 char 2
引用数据类型:类,接口,数组。。。。
[-128,127]放在常量池中
基础数据类型包装类
包装类都属于引用类型,函数参数需要是父类为Object的对象,所以基本数据类型需要包装类
char Character
int Integer
自动拆箱和自动装箱 包装类和基本数据类型之间会自动转换
但是使用==进行判断的时候不会自动拆箱,比较的是两个对象的地址
方法
带有static修饰的方法可以不创建对象直接调用 类名.方法()
否则需要创建对象 引用对象.方法()
修饰符列表(public/static等) 返回值类型 方法名 (形式参数列表){
方法体;
}
重载(Overload)
调用的参数不同,对应调用的方法不同
使用重载的情况:
功能相似的时候可以采用重载
满足什么条件构成重载
同一个类当中 / 方法名相同 / 参数不同(数量不同/顺序不同/类型不同)
String
底层是private final byte[ ] 所以每个用 ""括起来的内容都是字符串,放在方法区的常量池中。常量池中的字符串自声明起就不会改变,如果重新赋值会重新声明新的字符串到常量池中,是一个新的字符串对象。
采用new String()方法声明字符串会在堆内存中开辟一个指向常量池中的内存地址。
String s=new String(“xy”);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSl4DkAC-1649642398204)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220321101259847.png)]
String的方法
compareTo
endsWith
equalsIgnoreCase 判断是否相同且忽略大小写
getBytes 返回byte数组 字符对应的ASCII码
isEmpty 是否为空
substring
toCharArray 转换为char数组
toUpperCase toLowerCase
trim 去除字符串前后空白
第三章(面向对象)
三大特性:封装 继承 多态
new的类在堆内存中
java中 只能通过引用去访问堆内存中变量内部的实例变量
内存分析
1、JVM(Java虚拟机)主要包括三块内存空间,分别是:栈内存、堆内存、方法区内存。
2、堆内存和方法区内存各有1个。一个线程一个栈内存。
3、方法调用的时候,该方法所需要的内存空间在栈内存中分配,称为压栈。方法执行结束之后,该方法所属的内存空间释放,称为弹栈。
4、栈中主要存储的是方法体当中的局部变量。
5、方法的代码片段以及整个类的代码片段都被存储到方法区内存当中,在类加戮的时候这些代码片段会载入。
6、在程序执行过程中使用new运算符创建的java对象,存储在堆内存当中。对象内部有实例变量,所以实例变量存储在堆内存当中。
7、变量分类:
局部变量【方法体中声明】-成员变量【方法体外声明】
实例变量【前边修饰符没有static]*静态变量【前边修饰符中有static]
8.静态变量存储在方法区内存当中。
9、三块内存当中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收器主要针对的是堆内存。
10、垃圾回收器【自动垃圾回收机制、GC机制】什么时候会考虑将某个java对象的内存回收呢?
*当堆内存当中的java对象成为垃圾数据的时候,会被垃圾回收器回收。
*什么时候堆内存中的 java对象会变成垃圾呢?
没有更多的引用指向它的时候。
这个对象无法被访问,因为访问对象只能通过引用的方式访问。
封装
好处
1.将复杂的事物封装,提供简单的外部接口
2.封装之后才是真正的“对象”,真正的“独立体”
3.该段程序可独立使用,适应性强,其他场合可以使用
4.提高了安全性
步骤
1.属性私有化,只能在本类中使用
2、对外提供访问的接口
构造方法
作用
通过构造方法的调用可以创建对象,创建对象的同时初始化实例变量的内存空间
实例对象本身存放在java堆内存的内部 实例对象的引用地址:栈内存 实例对象的元数据class信息:方法区或元空间
如何调用
普通方法 有static时的调用格式: 类名.方法名(实参列表) 无static时: 引用.方法名(实参列表)
构造方法: new 构造方法名(实参列表)
返回值
返回构造生成对象在堆内存中的地址
代码块
public class StaticTest {
public static StaticTest t1=new StaticTest();
public static StaticTest t2=new StaticTest();
{
System.out.println("构造块");
}
static{
System.out.println("静态块");
}
public static void main(String[] args) {
StaticTest t=new StaticTest();
}
}
输出结果
构造块
构造块
静态块
构造块
静态代码块
static{
java语句;
}
静态代码块在类加载时执行且只此一次,一个类中可出现多个代码块,遵循自上而下的顺序执行
用途
在类加载时需要执行的内容 如:日志记录、数据准备工作(初始化连接池、解析XML文件)
实例代码块
main方法执行时不会执行,当实例代码块所在类的构造方法执行之前会被执行
继承
A is a B 表示继承 A是子类 B是被继承的父类
A has a B 表示类的属性 B是A的属性
子类先执行父类的构造方法再执行本身的构造方法
基本作用:代码复用
最重要的作用:方法的覆盖和多态机制
关键字 extends
子类从父类中继承的内容
私有的不继承
构造方法不继承
其余数据都继承
方法覆盖(方法重写)override
覆盖只针对方法不谈属性
使用情况: 当父类的方法不够子类的需求,子类需要对从父类继承的方法进行重写
书写要求: 子类在对方法重写时方法名要与父类相同,修饰的访问权限可以更高不能更低,抛出异常可以少不能多
静态方法不存在覆盖
多态
两转转换都需要前后两个类存在继承关系
向上转型(upcasting)
子类型转为父类型 自动类型转换 底层还是原来存在的子类型
编译通过 运行肯定不出问题
向下转型(downcasting)
父类型转为子类型 强制类型转换(需要加强制类型转换符)
强转时出现错误会出现 java.lang.ClassCastException 异常
instanceof运算符
为了避免 java.lang.ClassCastException 异常的出现
该运算符结果为true/false
a instanceof A true:a指向的对象确实是A类(指a的底层对象)
访问权限控制
修饰属性、方法
public 任意地方都能访问
protected 同包 子类中可以访问
缺省 default 同包下可以访问
private 只能在本类中进行访问
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gyrlOd0c-1649642398206)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220319131708416.png)]
修饰类
只有public和默认
第四章(抽象类与接口)
抽象类abstract
类和类之间具有共同特征,将这些共同特征提取出来形成抽象类
抽象类本身不存在,所以无法创建对象 属于引用数据类型
抽象类虽然不能实例化,但是有构造方法,供子类使用
正常类继承抽象类必须实现其中的抽象方法
抽象类中不一定有抽象方法
抽象方法
没有实现的没有方法体的方法 public abstract void dosome();
接口interface
架构师制定接口,各个类只需要关心接口 关联的类解耦合 可以分别编写
基础语法
接口是特殊的抽象类 —完全抽象
接口支持多继承,可继承多个接口
接口中只包含两部分内容:抽象方法、常量
接口中抽象方法public abstract可以省略 常量的public static final也可以省略
接口实现implements
与继承一样,实现方法访问权限只能更高。
如果继承和实现同时出现 extends在前implements在后
抽象类和接口的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x46scxTM-1649642398206)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220318190719316.png)]
第五章(各个方法)
equals函数
基本数据类型判断是否相等用==符号
引用数据类型判断用equals String为引用数据类型
public class TestEquals {
public static void main(String[] args) {
String a="avc";
String b="avc";
//true String如果相同会生成在常量池中 不会生成新对象 所以比较是相等的
//但如果String是new出来的不行
System.out.println(a==b);
System.out.println(a.equals(b));
MyTime mytime1=new MyTime(1);
MyTime mytime2=new MyTime(1);
//false 此处比较的是内存地址
//想要通过equals判断值相等要在类中重写
System.out.println(mytime1==mytime2);
System.out.println(mytime1.equals(mytime2));
}
}
class MyTime{
int year;
public MyTime(int year) {
this.year = year;
}
}
finalize方法
已被弃用
java对象被垃圾回收时会自动调用此方法
不需要调用 只需要重写
匿名内部类
不建议使用 只能使用一次
在方法中声明的类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XbW6HfH5-1649642398206)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220319215643311.png)]
第六章(数组+StringBuffer)
一维数组
数组是引用数据类型,放在堆内存中
如果存储的是“对象”,那么在数组中存放的是对象的引用(内存地址),数组中引用数据类型占4个字节
数组存储的内存地址是连续的
数组以第一个元素的地址作为整个数组的内存地址
优缺点
查询 存储 检索效率高
增删元素效率低,数组不能存储过大的数据 因为存储空间需要连续
数组初始化
//静态初始化
int[] array={100,200,300};
//动态初始化
int[] array=new int[5];
数组扩容
System.arraycopy(拷贝源,拷贝起始,拷贝目标数组,拷贝目标起始位置,拷贝长度)
数组工具类
java.util.Arrays
sort()方法
binarysearch()二分法查找
StringBuffer
java中字符串是不可变的 每一次拼接会产生新的字符串 所以需要StringBuffer
stringBuffer底层没有用final修饰 初始化为16个容量
字符串拼接 append()
线程安全
性能优化
创建StringBuffer时尽可能给定一个初始化容量
可以减少底层数组的扩容次数
StringBuffer sb=new StringBuffer(capacity); 指定初始化容量
StringBuilder
线程不安全 没有synchronized关键字修饰
Date
new Date(long) 自1970年起的毫秒数
date转String date函数显示时间格式化
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));
String转Date
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time="2008-08-08 08:08:08";
try {
Date datetime=sdf.parse(time);
System.out.println(datetime);
} catch (ParseException e) {
e.printStackTrace();
}
Decimal
DecimalFormat format=new DecimalFormat("###,###.##");
String s=format.format(1234.145134);
System.out.println(s);//1,234.15
DecimalFormat format2=new DecimalFormat("###,###.0000");
String s2=format2.format(1234.14);
System.out.println(s2); //1,234.1400
BigDecimal
java.math.BigDecimal
调方法进行计算
加法add
随机数
//int范围内的随机数
Random random=new Random();
int num1=random.nextInt();
//100以内的随机数 不包括100
int num2=random.nextInt(100);
第七章(异常)
Object
Trowable
Error Exception
virtualMachineError IOError || exception直接子类(编译时异常) RuntimeException(运行时异常)
StackOverflowError
编译时异常表示必须在编译时就提前处理,否则不能运行
throws和trycatch
希望调用者自己处理的用throws 其余的采用trycatch
异常报错提示
e.pritStackTrace();
finally
try语句即使出现了问题 finally中的语句也会执行
资源流的关闭 资源的回收
自定义异常
定义一个无参构造和一个带String的构造方法
这个String可以通过 getMessage方法进行获取
第八章(集合)
ArrayList 非线程安全
Vector 线程安全 效率较低 较少使用
HashSet 底层其实是创建了HashMap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GE04afvp-1649642398207)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220326195623422.png)]
总结(所有的实现类):
ArrayList:底层是数组。LinkedList:底层是双向链表。
LinkedList:底层是双向链表
Vector:底层是数组,线程安全的,效率较低,使用较少。
HashSet:底层是HashMap,放到HashSet,集合中的元素等同于放到HashMap集合key部分了。
TreeSet:底层是TreeMap,放到TreeSet,集合中的元素等同于放到TreeMap,集合key部分了。
HashMap:底层是哈希表。
Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。
properties:是线程安全的,并且 key和value只能存储字符串String。
TreeMap:底层是二叉树。TreeMap集合的 key可以自动按照大小顺序排序。
Collection
iterator集合只要发生改变 迭代器必须重新获取
在迭代过程中可以通过迭代器来删除元素 但不能通过collection来删除
Collection c=new ArrayList();
c.add(new String("abc"));
c.add("def");
c.add(3.14);
c.add(new Object());
Iterator it=c.iterator();
//hasNext()
//next()
//size()
//contains 比较的是内容 底层调用的equals
String s=new String("abc");
System.out.println(c.contains(s));
while(it.hasNext()){
System.out.println(it.next());
}
List
常用方法
void add(int index , Object element)
Object get(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
Object remove(int index)
Object set(int index , Object element)
ArrayList
扩容是原容量的1.5倍 底层是数组
尽量减少扩容次数 效率低
Vector
扩容是两倍
所有方法都是线程安全的
HashSet
初始化容量16 扩容为原容量2倍
容量建议为2的倍数 有利于提高效率
TreeSet
底层为TreeMap 为二叉树
无序不可重复(存入取出的顺序无序) 可以按照元素大小顺序自动排序
TreeSet无法对自定义的类型进行排序
需要对自定义的类中实现Comparable接口
Comparable
@Override
public int compareTo(Customer o) {
return this.age-o.age;
}
Comparator
当比较规则不会发生改变时用Comparable 如果有多个规则之间频繁切换用Comparator
泛型
new ArrayList() 表示该List中只能存储该类型的数据
元素类型统一
JDK8之后可以自动推断泛型类型
List myList=new ArrayList<>();
Collections工具类
1、Collections.synchronizedList( )是的ArrayList线程安全
2、Collections.sort( )只能是List集合 但是Set集合可以封装成List集合
List mylist=new ArrayLast<>(set);
Map
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwFL8I6c-1649642398207)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220326200757779.png)]
Set<Map.Entry<Integer,String>> entry=map.entrySet();
for (Map.Entry<Integer,String> node:entry
) {
System.out.println(node.getKey()+node.getValue());
}
这个方式更快,避免重复获取key和value,直接将map中的entrySet放入Set中
HashMap
需要重写hashCode方法 避免将相同的元素因比较的是地址不同而重复存储
public int hashCode(){
return Objcects.hash(name);
}
Hashmap中的key可以为空,但只能有一个 因为会重复
HashTable
hashTable不允许key和value为空
Properties
是一个Map的集合,继承HashTable key和value都是String
被称为属性类对象,是线程安全的
第九章(IO流)
输入流 输出流
字节流 字符流
java.io
以Stream结尾的都是字节流
Reader/Writer结尾的是字符流
Closeable可关闭 流使用完记得关闭
输出流 flush( ) 管道清空
默认当前路径
工程Project的跟就是IDEA的默认当前路径
文件专属
java.io.FileInputStream
read() 读一个字节
read(byte[ ]) 返回读取到的字节数量
文件中的内容为 abcdef
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tlgKIJtF-1649642398207)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220401144739232.png)]
available()还剩多少个字符没读 不适合过大的文件使用
skip()跳过几个字节不读取
java.io.FileOutputStream
用byte[ ]进行读取
文件字节输出流 负责写文件
输出流写完要刷新
true表示在目标文件后追加,false或不写表示清空源文件
fos=new FileOutputStream("src\\JavaLearning\\IOLearning\\tempfile.text",true);
java.io.FileReader
用char[ ]进行读取
java.io.FileWriter
无法读取word 图片 视频等流媒体文件
能用记事本编辑的是文本文件
转换流:将字节流转换为字符流
java.io.InputStreamReader
Input是字节流 Reader是字符流
// //字节流
// FileInputStream in=new FileInputStream("src\\JavaLearning\\IOLearning\\FileWriterTest01.java");
// //字节流转为字符流
// InputStreamReader reader=new InputStreamReader(in);
// //BufferedReader只能传字符流
// BufferedReader br=new BufferedReader(reader);
//写成一行
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("src\\JavaLearning\\IOLearning\\FileWriterTest01.java")));
java.io.OutputStreamWriter
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("src\\JavaLearning\\IOLearning\\FileWriterTest01.java")));
缓冲区专属:
java.io.BufferedReader
只能传字符流 不能穿字节流
FileReader reader=new FileReader("src\\JavaLearning\\IOLearning\\FileWriterTest01.java");
//当一个流的构造方法中需要一个流的时候,被传入的流叫做节点流
//外部负责包装的叫包装流 或处理流
//FileReader 节点流 BufferedReader 保留装/处理流
BufferedReader br=new BufferedReader(reader);
//readline方法读的时候不带换行符
String fr=br.readLine();
System.out.println(fr);
String sec=br.readLine();
System.out.println(sec);
//只需要将外部的流关闭就可以 会调用in.close()方法
br.close();
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
数据流专属:
java.io.DataInputStream
java.io.DataOutputStream
将数据连同数据类型一并写入文件
//专属的字节输出流 完成写入的文件只能通过DataInputStream并且以相同的输入方式才能读出
DataOutputStream dos=new DataOutputStream(new FileOutputStream("data"));
//writeBoolean
//writeByte
DataInputStream dis=new DataInputStream(new FileInputStream("data"));
标准输出流:
java.io.ObjectInputStream
java.io.ObjectOutputStream
对象专属流:
java.io.PrintWriter
java.io.PrintStream
File类
文件和路径的抽象表示形式
file.mkdir()以目录的形式新建文件
file.mkdirs()以多重目录的形式新建文件
file.getname()获取文件名
通过文件目录的File文件 可以通过listFiles()方法来获取File[ ]集合 再通过foreach进行遍历
序列化
- 序列化:把Java对象转换为字节序列的过程。
- 反序列化:把字节序列恢复为Java对象的过程。
参与序列化与反序列化的类必须实现Serializable接口 java虚拟机会生成一个序列化版本号
该接口源码没有内容只是一个标志接口
通过list集合存储反序列化的文件
加入transient表示该字段不参与序列化
private static final long SerialVersionUID
Properties
经常改变的数据可以通过以下方式获取 存储在文件中
类似于以上机制的文件叫配置文件
FileReader reader=new FileReader(" ")
Properties pro=new Properties();
//文件内容为key=value形式进行读取
pro.load(reader);
String username=pro.getProperties("username");
第十章(多线程)
线程基础
进程和线程
进程是一个应用程序
线程是一个进程中的执行场景或执行单元
一个进程可以启动多个线程
线程堆内存和方法区共享 但是栈内存独立
线程的start()方法
start方法的作用是在JVM中开辟一个新的栈空间,瞬间就能完成,启动成功的方法会自动调用run方法,并且该方法在分支栈的底部。
没有用start方法而只是单纯的run线程 不会新建分支线程,只会在主线程中运行
实现线程的两种方法
1、extends Thread 并重写run方法
MyThread myThread=new MyThread();
myThread.start();
2、implements Runnable 并重写run方法
第二种方式更常用 不耽误对其他类的继承
Thread t=new Thread(new MyRunnable());
t.start();
线程的生命周期
新建——》调用start方法——》就绪状态(表示当前线程具有强度CPU时间片的权利)——》运行状态(run方法的开始执行标志着这个线程进入运行状态)(如果CPU时间片用尽会回到就绪状态并继续强度CPU时间片,抢夺到了继续之前运行的进度继续执行)——》死亡状态(run方法执行结束标志着线程进入死亡状态)
线程对象相关方法
currentThread 获取当前线程
sleep方法 让当前线程进行休眠 和调用的对象无关
run方法中的异常只能try catch 子类不能比父类抛出更多的异常
interrupt 唤醒睡眠的线程 依靠的是java的异常处理机制 唤醒之后会报异常
终止线程的运行 通过静态外部变量来控制线程的执行判断条件
线程调度
抢占式、均分式
void setPriority(int)默认为5 最高优先级10 最低1
yield 暂停当前线程 并执行其他方法 让当前线程回到就绪状态 不是阻塞
合并线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDMmm9pt-1649642398208)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220405155653126.png)]
线程安全
同步和异步
异步:多线程并发
同步:两个线程排队执行 有等待关系
synchronized(此处填写的是所需要锁定的共享对象){
}
在实例方法上也可以加synchronized 锁在方法上时锁的是this 整个方法体都被同步 会扩大范围 效率低
死锁
public class DeadLock {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
Thread t1=new MyThread1(o1,o2);
Thread t2=new MyThread2(o1,o2);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o1){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
System.out.println(1);
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o2){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
System.out.println(2);
}
}
}
}
守护线程
setDaemon(true)将线程设置为守护线程,主线程结束之后自动结束(不管是否有内容)
定时器
public class TimerTest {
public static void main(String[] args) throws Exception {
Timer timer=new Timer();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime=sdf.parse("2022-04-06 16:30:10");
timer.schedule(new LogTimerTask(),firstTime,1000*10);
}
}
class LogTimerTask extends TimerTask{
@Override
public void run() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strtime=sdf.format(new Date());
System.out.println(strtime);
}
}
实现线程的第三种方式
实现Callable接口
FutureTask
public static void main(String[] args) throws Exception{
FutureTask future=new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
System.out.println("callable method begin");
Thread.sleep(5000);
System.out.println("call Method end");
int a=100;
int b=200;
return a+b;
}
});
Thread t=new Thread(future);
t.start();
//可能会导致当前线程受阻 因为需要等待线程结束得到执行结果
Object obj= future.get();
System.out.println("helloWorld");
}
notify和wait
wait能作用于任意Object对象 让该线程进入无线等待状态
notify方法唤醒该对象上等待的线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFU4vvT6-1649642398208)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220406195200956.png)]
生产者和消费者
第十一章 (反射)
反射机制
可以通过放射机制操作字节码文件
Class.forName( )
通过反射机制创建对象,比直接new要灵活
FileReader reader=new FileReader("sampleStore\\classinfo.properties");
Properties pro=new Properties();
pro.load(reader);
reader.close();
String className=pro.getProperty("className");
Class c=Class.forName(className);
Object obj=c.newInstance();
可以通过反射机制调用静态代码块
文件路径
该方法获取的是绝对路径 项目src作为起点
String path=Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath();
ResourceBundle
可以直接获取properties文件的信息
填文件名称时不带properties后缀
获取Class的三种方式
Class.forName
对象.getClass
int.getClass/String.getClass
获取Field
Field为类的相关信息
通过类调用方法 getFields 获取所有公开的属性
getDeclaredFields( ) 获取所有的
field.getModifiers( )获取类的访问权限
field.getType( ).getSimpleName( )
使用反射机制给对象赋值
//获取num属性
Field field=studentClass.getDeclaredField("num");
//对obj对象的num属性赋值222
field.set(obj,222);
可变长度参数
//args可作为数组 可以放多个参数
public void m(int... args){
}
invoke
返回值=方法.invoke(对象,所需的实参)
通过反射机制创建对象
Class c=Class.forName("JavaLearning.Reflect.Vip");
Constructor con= c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
Object newObj=con.newInstance(110,"jackson","1999-07-24",true);
第十二章(Annotation)
Override
在java中如果方法上加@Override的注解的话,表示子类重写了父类的方法。
Deprecated
这个方法或类不再建议使用。在新版本中有其他方法或类可以代替这个使用,以后的版本也不会再更新这个方法或类
Target
用于描述注解的使用范围
Retention
被它所注解的注解保留多久
source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
面试题
1、最底层用native关键字调用C++编写的,那些方法没有方法体。
如Object中存在的方法 public native int hascode();
2、new对象必定在堆内存中开辟空间
3、常量池
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afTUINYb-1649642398209)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220321103728403.png)]
4、Integer [-128,127]范围内的数字生成在常量池中,不会重复生成对象
5、String int Integer相互转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JKA1es1-1649642398209)(C:/Users/CLY/AppData/Roaming/Typora/typora-user-images/image-20220324160232770.png)]
6、final finally finalize的区别
final是一个关键字 表示最终的不变的
finally与try连用 必定执行
finalize()是Object中的一个方法 finalize是一个标识符
7、