一、java基础
1、jdk、jre、jvm区别
- jdk:java开发工具箱
- jre:java运行时环境
- jvm:java虚拟机
jdk > jre >jvm,jvm无法独立安装,jdk和jre能独立安装。
2、java的编译阶段和运行阶段
编译阶段
- 源代码以.java结尾
- 编译后得到以.class结尾的字节码文件
- class文件非二进制文件,其需要通过jvm翻译成二进制文件
- 生成的class文件可以在任何安装了虚拟机的机器上运行
运行阶段
类加载器加载class文件,运行程序。
3、jdk安装和往期版本区别
- jdk8安装时会内置一个jre,并且在目录下再生成一个jre。
- jdk13安装时只会内置一个jre,并不会在目录下再生成一个jre,可以通过特殊命令让其生成。
4、环境变量path配置
path作用:给操作系统指路,指定到哪个文件夹中寻找文件。
为了能在cmd中运行java命令,需将java的bin路径配置到path中。
5、classpath环境变量配置
作用:给类加载器指路。
如果配置了classpath,则类加载器只会在classpath路径中寻找类文件。
6、编码发展
- ASIIC编码 不支持中文
- ISO-8859-1 不支持中文
- GB2312
- GBK
- GB18030
- Big5 繁体中文
- unicode(utf8 utf16 utf32)//支持世界上所有字符的编码。
7、类型转换
- 整型整数常量默认为int类型,若要表示成long则需在数字后面加L或l。
- 浮点型默认为double,若要表示成float则需要数字后面加F/f。
- 基本类型容量大小排序:byte<short(char)<int<long<float<double
- 自动类型转换:小转大。
- 强制类型转换:大转小,如果不超过小的范围,则可以省略强转步骤。
- 引用:存放堆内存地址的变量。
- 只有基本类型才有强制类型转换和自动类型转换。引用类型转换分为向上转型和向下转型。
8、public class注意事项
一个.java文件中只能有一个public class,且该public class的类型必须与文件名相同。
一个.java文件中可以有多个class,编译时会产生各自的.class文件。
9、Jvm内存
注:方法,不管静态方法、实例方法、构造器,执行时都需要压栈,从栈中分配空间。
10、函数
函数签名:函数名(参数...),其作为函数的唯一标识。
函数重载:相同函数名但参数不同(参数的类型或参数的个数不同),可以实现函数的重载。返回值不同无法构成重载。
函数重写:子类重写父类方法。
11、OOA、OOD、OOP
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
12、成员变量(实例变量)默认值
13、static关键字
静态变量
定义:static修饰的成员变量。
内存分配:在方法区中分配一块内存,并且会进行默认初始化。
使用:可用对象.静态变量或者类.静态变量,推荐后者。
静态方法
定义:static修饰的方法。
内存分配:执行时进行压栈。
使用:可用对象.静态方法或者类.静态方法,推荐后者。
静态代码块
定义:static修饰的代码块
举例:
static{
System.out.println();
code...
}
执行时机:类加载时执行,且仅执行一次。
作用:进行初始化操作,打印类加载日志等。
实例代码块
{
代码
}
执行时机:在构造方法执行之前执行。
作用:可将各个构造器中相同的代码提取到实例代码块中。
14、this关键字
定义:this是一个引用,每个对象都有一个这样的引用,该引用存储的地址为当前对象的内存地址。
作用:实例变量的访问必须使用如下格式:引用.实例变量。类的实例方法中想要调用当前对象的实例变量,需使用this.实例变量。this.可以省略。
不能省略的情况:当局部变量的变量名与实例变量名相同时,为了区分这两个变量,则this.不能省略。
this():构造器中可调用类的其他构造器,可以通过this()进行调用,且this()只能出现在构造方法的第一行。作用是可以省略相同的代码。
15、多态
定义:父类型引用指向子类型对象。
方法静态绑定定义:编译阶段绑定方法。
方法动态绑定定义:运行阶段绑定方法。
多态编译阶段:绑定父类的方法。
多态运行阶段:动态绑定子类型对象的方法。
16、instanceof
作用:运行阶段动态判断对象的类型。
语法:对象 instanceof 类型
注意:每次进行类型转换之前,要进行一次instanceof判断,防止出现强转异常。
17、重写后方法的返回值类型
- 对于返回值类型是基本数据类型的方法,重写之后返回值必须一致。
- 对于返回值类型是引用数据类型的方法,重写之后返回值类型可以变得更小。
18、super关键字
- super作用:通过super.调用父类方法,通过super()调用父类构造器。
- 当子类构造方法没有this()和super()的时候,默认会有一个super(),表示调用父类的无参构造方法。
- this()和super()不能共存,因为两者都出现在构造方法的第一行。
- 子类的构造方法中,一定会执行父类的构造方法。虽然执行父类的构造方法,但不会创建父类对象,整个过程只创建我们指定的对象。调用父类构造器是为了初始化父类型特征。
- super代表的是父类型的那部分特征。
- super不能省略的情况:java中允许父类和子类出现相同的属性名。故需要调用父类的属性名与子类属性名相同的属性时,super不能省略。方法也是如此。
- super不是引用,也不保存内存地址,不指向任何对象。
二、java进阶
1、idea开发工具
任何添加操作:alt+insert
运行程序:ctrl + shift + f10
切换窗口:alt + 序号
展开文件夹:右方向键
关闭文件夹:左方向键
文件窗口切换:alt + 左右方向键
删除一行:ctrl + y
参数提示:ctrl + p
2、final关键字
final修饰的变量:无法重新赋值
final修饰的方法:无法重写
final修饰的类:无法继承
final修饰的变量一定要赋值。
常量:static final修饰的变量称为常量。其本质也是一个静态变量,只是其不可修改。
3、抽象类
抽象类无法实例化,但有构造方法,其作用是供子类使用。
抽象类的子类可以实抽象类。
final和abstract无法联用。
抽象类中不一定有抽象方法,但抽象方法一定出现在抽象类中。
4、接口
一个接口可以继承多个接口,支持多继承。
接口中只有两样东西:常量和抽象方法。
接口中的抽象方法定义时:public abstract可以省略。
接口中的常量:public static final 可以省略
接口a和接口b没有继承关系,其两者也可以进行强制类型转换,编译器不会报错,但是运行时可能会抛出异常。
5、类与类的关系
is a:继承关系
has a:关联关系
like a:实现关系
6、访问修饰符
访问修饰符 | 本类 | 同包 | 子类 | 任意位置 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认 | 可以 | 可以 | 不可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
属性、方法四个访问修饰符都能用。
接口和类只能用public和默认。
7、object几个重要的方法
- protected object clone():负责克隆。
- int hashCode():底层调用c++程序返回java对象内存地址。
- boolean equals(Object obj):默认比较两个对象的内存地址
- String toString():默认为类名+@+内存地址
- protected void finalize():对象被回收之前垃圾回收器自动调用此方法,默认为空方法体。jdk9之后此方法已被废弃。
8、内部类
- 静态内部类
- 实例内部类
- 局部内部类:包含匿名内部类。
9、数组
数组也是一个类,默认继承object。常用属性length。
数据拷贝方法:System.arraycopy();
数据工具类:java.util.Arrays。常用方法:sort。
10、String类
- 凡是用“”包起来的字符串,其都是在方法区中的字符串常量池中创建出String对象,String变量只是存储了方法区中字符串的地址。
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);//结果为true,因为s1和s2都是存储了方法区字符串常量池中"hello"的内存地址。
String t1 = new String("hello");
String t2 = new String("hello");
System.out.println(t1 == t2);//结果为false,因为t1和t2存储的是堆中各自String对象的内存地址。
- 判断字符串是否相等,建议如下使用如下格式:
"hello".equals(s1);//可以避免空指针异常
11、StringBuffer类
底层是一个byte数组,默认大小为16。
优化性能的方法:预估字符串大小,初始化StringBuffer的容量。
12、StringBuilder类
与StringBuffer类类似,只是它所有的方法都有synchronized修饰,所以它能保证线程安全。
13、Integer类
Integer相同值的引用一般都是不同的,但是值为-128127的引用是相同的,因为-128127的Integer被保存在了方法区的整型常量池。Integer类加载的时候就会初始化这个整型常量池。
14、int、String、Integer互转
15、日期
Date创建时间
SimpleDateFormate类中的format和parse进行日期和字符串转换。
System.currentTimeMillis():获取自1970年1月1日到系统当前时间的总毫秒数。
System.exit(0):退出JVM。
16、DecimalFormat
作用:格式化数字输出。
使用范例:
//###,##.0000,表示:加入千分位,保留四位小数,位数不够补零
DecimalFormat df = new DecimalFormat("###,##.0000");
String s = df.format(1234.56);
System.out.println(s);//输出1,234.56
17、BigDecimal
定义:精度极高的大数据,主要用于财务类。
注意:使用该类进行运算时,需要使用方法计算,因为该类没有自动装箱和拆箱。
18、枚举类型
enum{
枚举值1,枚举值2,...
}
19、错误与异常
异常
-
发生阶段:所有都发生在运行阶段。
-
编译时异常/受控异常/受检异常:编写代码阶段就必须处理异常,否则编译不通过,所有的Exception子类都属于编译时异常。
-
运行时异常/非受控异常/未受检异常:代码编写阶段没有强制性要求处理异常,所有的RuntimeException都属于运行时异常。
-
异常两种处理方式:try catch 或者 throws,两种方式的选择原则:如果需要调用者处理异常,则throws,否则try catch。
20、finally
finally语句一定会执行,除非使用System.exit(0)退出JVM虚拟机。
try{
System.out.println("try");
return;
}finally{
System.out.println("finally");
}
//输出为:tryfinally,因为会先执行finally中的语句再return。
21、final、finally、finalize
final:关键字,表示不可变
finally:关键字,与try连用
finalize:Object的一个方法名,是一个标识符。
22、集合
- 集合不能直接存储基本数据类型,其存储的是引用,即内存地址。
-
contains()方法:通过equals方法进行比较的,只要两个元素的equals比较之后相同,则判定为两个元素相同。
-
remove()方法:底层也是调用equals。
23、Collection和Collections的区别
Collection是一个接口,Collections是一个工具类。Collections的synchronizedList()可以返回一个线程安全的列表。
24、泛型机制
- 泛型机制是jdk5之后才有的。
- 泛型只在程序编译阶段起作用,运行阶段不起作用。
- 自定义泛型作用,让调用者决定某些值的类型,类似参数或者函数返回值。
25、foreach循环
语法:
int[] arr={1,2,3,4,5};
for(int i: arr){
System.out.println(i);
}
使用对象:可以是数组,也可以是集合。
26、HashMap
- HashMap建议初始化大小为2的指数。
- HashMap中元素的插入执行:先执行hashCode()求得hashmap下标,再通过equals方法进行比对插入。
- HashMap和HashSet中的元素,必须同时重写hashCode和equals方法。
- jdk8之后,如果hash表单向链表中的元素大于8个,则该单向链表会编程红黑树,若小于6,则会重新变成单向链表。
- HashMap默认大小为16,默认加载因子为0.75。
- HashMap的key允许为空,且key为null的值只能有一个,多次put(null,值)会覆盖原先的值。
27、Hashtable
- Hashtable的key和value都不能为null。HashMap的key和value都可以为null。
- Hashtable的默认大小为11,默认加载因子为0.75。
- Hashtable扩容:原容量*2+1。
28、Properties
- Properties是一个Map集合,其key和value都是String类型。
- Properties被称为属性对象类。
- Properties是线程 安全的。
29、TreeSet
TreeSet插入的元素会根据比较器进行自动排序。故要么其类继承Comparable接口,要么继承Comparator写一个比较器类实现。
30、Comparable和Comparator的比较
比较规则不会发生改变,或比较规则只有一个,采用Comparable。
如果比较规则频繁切换,则使用Comparator。
三、IO流
1、IO流的分类
按输入输出分:输入流、输出流。
按字节字符分:字符流(txt)、字节流。
2、IO所属包
java.io.*;
3、IO流四大家族(皆为抽象类)
java.io.inputStream:字节输入流
java.io.outputStream:字节输出流
java.io.Reader:字符输入流
java.io.Writer:字符输出流
四大接口都实现了Closeable接口,每次操作完后记得调用close()方法。
所有的输出流都实现了Flushable接口,每次输出完之后需要刷新,清空缓冲区。
Reader、Writer只能读取普通文本,即类似.txt文件
注意:在java中只要“类名”以Stream结尾的都是字节流;以“Reader/Writer”结尾的都是字符流。
4、常用的16个IO流
文件流:
FileInputStream
FileOutputStream
FileReader
FileWriter
转换流:
InputStreamReader
OutputStreamWriter
缓冲流:
BufferedInputStream
BufferedOutputStream
BufferedWriter
BufferReader
数据流:
DataInputStream
DataOutputStream
标准输入输出流:
PrintWriter
PrintReader
对象专属流:
ObjectInputStream
ObjectOutputStream
5、常用方式示例代码
FileInputStream fis = new FileInputStream("inputFile.txt");
FileOutputStream fos = new FileOutputSteam("outputFile.txt");
byte[] buffer = new byte[1024];
int readCount = 0;
while((readCount = fis.read(buffer)) != -1){
fos.write(buffer);
}
InputStream需要了解的方法:availables(获取未输出的字符个数)和skip(跳过n个字节)。
向文件追加,不是覆盖文件,则采用FileInputStream(String fileName, boolean append)方式。
6、File类
定义:file类是目录和文件路径的一种抽象表现形式。
常用方法:
exists();
createNewFile();
getAbsolutePath();
getAbsolutePath();
getName();
getPath();
getParent();
getParentFile();
isDirectory();
isFile();
lastModified();
listFiles();
mkdir();
mkdirs();
文件拷贝:通过递归方法拷贝。
7、序列化Serializable
-
java对象要输出到内存,需要进行序列化,然后调用 ObjectOutputStream进行输出。
-
要进行序列化的对象,需要实现Serializable接口。
-
Serializable接口内部没有方法,其只是起到一个标志的作用。Java中的接口有两类,一类是带有方法的接口,一类是标志类接口。
-
Java虚拟机会为实现序列化接口的对象生成自动生成一个序列化版本号。
-
transient关键字
用transient关键字修饰的属性,其不会被序列化。
-
序列号
作用:用来去分类。类的区分:通过类名,类名相同再通过序列号进行区分。
注意事项:当一个类的代码被修改过后,java虚拟机自动生成的序列号会因此而改变,若将先前该类的序列化对象反序列化则会报错,因为序列号改变了。故建议手动设置序列号,不要自动生成。
private static final long serialVersionUID = 1L;
8、Properties和IO流
java中将一些经常修改的东西提取到配置文件中,防止多次修改代码重新编译。配置文件通常以.properties结尾。只有Properties内容为:key=value。
与IO流搭配用法范例:
FileReader fr = new FileReader("userinfo.properties");
Properties properties = new Properties();
properties.load(fr);
String name = properties.getProperty("username");
四、多线程
线程的三个性质:原子、可见、有序
1、内存分配:Java中的线程共用堆内存和方法区。每个线程都有自己的一个栈内存。
2、开启线程的三种方式:
①写一个类继承Thread,重写run方法,在run方法中编写要执行的代码。然后new该类,并调用start()方法开启线程。run方法与main方法功能类似,都位于栈底。
②编写一个类实现Runnable接口,重写run()方法。new Thread并new先前的类作为参数传递进去。实现Runnable的类称为可运行类,并非线程类。
③将②方式简化成匿名内部类。
3、线程的生命周期
新建状态
就绪状态
运行状态
阻塞状态
死亡状态
4、线程名称
获取线程名称:String name = 线程对象.getName();
设置线程对象的名字:线程对象.setName("线程名字");
获取当前线程对象:Thread thread = Thread.currentThread();
sleep()方法使用:Thread.sleep(long millis)方法可以让当前线程进入阻塞状态。
中断线程睡眠:线程对象.interrupt()。该方式通过异常处理机制中断睡眠。
终止线程执行:stop方法已被废弃。一般采用一个标志位run,当run为false终止线程执行。
class MyRunnable implements Runnable{
//标志位
boolean run = true;
@override
public void run(){
if(run){
//线程中代码
}else{
//结束前执行代码
code...
return;
}
}
}
5、join方法(线程合并)
让当前线程阻塞并执行线程体中的内容。
class MyThread1 extends Thread{
public void doSome(){
MyThread2 t = new MyThread2();
t.join();//阻塞当前线程,执行t线程。
}
}
class MyThread2 extends Thread{
}
6、设置线程优先级
线程对象.setPriority(int priority);//1最低,10最高,默认5。
线程优先级只是提高调度的可能性。
7、yield让位线程
Thread.yield();让渡cpu,使该线程回到就绪状态。
8、线程安全synchronized
使用方式:
①synchronized(共享对象){
需要同步执行的代码,即同步代码块
}
②加在实例方法上,修饰方法,此时默认加锁的共享对象为this。
③加在静态方法上,锁的是类。
本质:synchronized是通过加锁的机制实现同步。
局部变量不会有线程安全问题。实例变量和静态变量会有线程安全问题。
synchronized所的是方法,并不是锁共享对象,共享对象中未加synchronized的其他方法不受锁的影响。
死锁构建代码:
嵌套使用synchronized能导致死锁,一般不建议嵌套使用synchronized。
public class DeadLock{
public static void main(String[] args){
Object o1 = new Object();
Object o2 = new Object();
MyThread1 t1 = new MyThread1(o1, o2);
MyThread2 t2 = new MyThread2(o1, o2);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object obj1;
Object obj2;
public MyThread1(Object obj1, Object obj2){
this.obj1 = obj1;
this.obj2 = obj2;
}
@overried
public void run(){
synchronized(obj1){
Thread.sleep(1000);
synchronized(obj2){
}
}
}
}
class MyThread2 extends Thread{
Object obj1;
Object obj2;
public MyThread2(Object obj1, Object obj2){
this.obj1 = obj1;
this.obj2 = obj2;
}
@overried
public void run(){
synchronized(obj2){
Thread.sleep(1000);
synchronized(obj1){
}
}
}
}
9、守护线程
Java中的线程分为两类:用户线程、守护线程(后台线程)。main方法是一个用户线程;守护线程典型例子:垃圾回收线程。
守护线程特点:通常是一个死循环,所有用户线程结束了,守护线程自动结束。
设置为守护线程:线程对象.setDaemon(true);
10、定时器
Timer timer = new Timer();
timer.schedule(new TimerTask(){
@override
public void run(){
//code...要执行的代码
}
},firstTime, period);
11、实现线程的第三种方式FutureTask
实现Callable接口。
优点:可以获取线程的返回值。
缺点:效率低,会阻塞当前线程。
FutureTask task = new FutureTask(new Callable(){
@override
public Object call(){
int a = 10;
int b = 5;
return a+b;
}
});
Thread t = new Thread(task);
t.start();
Object obj = task.get();//获取线程返回值
12、Object的wait()和notify()方法
wait和notify方法是所有java对象都有的。
wait()的作用:
Object o = new Object();
o.wait();
表示:让o对象所在的线程进入等待状态,直至被唤醒。
notify()作用:
o.notify();
表示:唤醒o对象所在的线程。
类似的有o.nofityAll(),唤醒o对象上所有的等待线程。
五、反射
1、反射机制的作用
可以操作字节码文件。
所属的包:java.lang.reflect.*;
常用的类:
java.lang.Class; 代表字节码文件
java.lang.reflect.Method;
java.lang.reflect.Field;
java.lang.reflect.Constructor;
字节码文件即类的Class对象是保存在方法区中的。
2、获取Class的三种方式
①Class.forName("完整类名");
②对象.getClass();
③类.class;
3、类加载
Class.forName();这个方法的执行会导致类加载,从而导致静态代码块的执行。
4、类路径
凡是在src目录下的都是类路径。src是类路径的根路径。
5、获取路径的通法
String path = Thread.currentThread().getContextClassLoader()
.getResource("相对于根路径的路径").getPath();
//currentThread()获取当前线程
//getContextClassLoader获取当前类加载器
//getResource()类加载器的方法,从类根路径下加载资源
InputStream is = Thread.currentThread().getContextClassLoader()
.getResouceAsStream("相对于根路径的路径");
//该方式直接以流的形式返回资源,省去了转换为流的步骤
6、资源绑定器ResourceBundle
资源绑定器只能绑定XXX.properties文件,并且该文件必须在类路径下,文件扩展名也必须是properties,在写路径时,路径的扩展名要省略。
ResourceBundle bundle = ResourceBundle.getBundle("com/joygin/java/userInfo");
String className = bundle.getString("className");
System.out.println(className);
7、类加载器
类加载器有3类
启动类加载器、扩展类加载器、应用类加载器
类加载器执行
代码执行之前,会将需要的类全部加载到JVM中。首先通过启动类加载器,加载rt.jar中的类。再通过扩展类加载器加载ext文件夹下所有包的类。再通过应用类加载器加载classpath中的类。
启动类加载器:专门加载rt.jar。
扩展类加载器:专门加载ext文件夹下的类。
应用类加载器:专门加载classpath中的类。
双亲委托机制
java为了保证类的安全,使用双亲委托机制,即优先从启动类加载器中加载即“父类加载器”,再从扩展类加载器中加载即“母类加载器”,如果双亲中都找不到,则再从应用类加载器中加载。
8、可变长度参数
语法:类型... (一定要加三个点)
eg:int... args
注意:可变长度参数只能放在参数末尾。
本质:当作一个数组看待。
9、反射机制调用方法
10、反射机制调用属性
11、反射获取父类
Class stringClass = Class.forName("java.lang.String");
Class superClass = stringClass.getSuperClass();
12、反射获取接口
Class[] interface = stringClass.getInterfaces();
六、注解
注解,又称注释类型。英文名为:Annotation,本质是一种引用数据类型,编译后也会产生xxx.class文件
自定义注解
【修饰符列表】 @interface 注解类型名{
}
注解使用
使用格式:@注解类型名
使用地方:可以出现在类上、属性上、方法上、变量上,还可以出现在注解类型上。
元注解
定义
用来修饰注释类型的注解称为元注解。
常用的元注解:
Target:用来指示注解可以修饰的东西,即出现的位置。例如:
@Target(ElementType.Method)
//表示该注解只能出现在方法上。
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
//表示该注解剋有出现在构造器、属性等位置上。
Retention:用来指示注解最终保存在哪里。
@Retention(RetentionPolioy.SOURCE):表示该注解只被保留在java源文件中。
@Retention(RetentionPolioy.CLASS):表示注解被保存在java源文件中,并且编译保存到class文件中。
@Retention(RetentionPolioy.RUNTIME):表示注解被保存在class文件中并且可以通过反射机制读取。
注解自定义属性
注解中自定义属性格式:
类型名 属性名(); //不带默认值,使用时则必须为该属性赋值
类型名 属性名() default 默认值; //带默认值,使用时不必强求赋值
eg:
String name();
int age default 25;
技巧:
①当注解中的属性有且只有一个并且该属性名为value,则使用该注解时,属性名value可以省略。
②当注解中的属性类型为数组,则使用数组时,如果传入的数组只有一个值,则可以省略掉大括号。
注解的作用
配合反射机制,可以起到约束作用等。
反射机制获取Annotation,代码: