一、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内存

image-20200930190547286

image-20200930201051939

image-20200930201803937

注:方法,不管静态方法、实例方法、构造器,执行时都需要压栈,从栈中分配空间。

10、函数

函数签名:函数名(参数...),其作为函数的唯一标识。

函数重载:相同函数名但参数不同(参数的类型或参数的个数不同),可以实现函数的重载。返回值不同无法构成重载。

函数重写:子类重写父类方法。

11、OOA、OOD、OOP

OOA:面向对象分析

OOD:面向对象设计

OOP:面向对象编程

12、成员变量(实例变量)默认值

image-20200930200912620

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、重写后方法的返回值类型

  1. 对于返回值类型是基本数据类型的方法,重写之后返回值必须一致。
  2. 对于返回值类型是引用数据类型的方法,重写之后返回值类型可以变得更小。

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互转

image-20201004222504820

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、错误与异常

image-20201005003737432

异常

  • 发生阶段:所有都发生在运行阶段。

  • 编译时异常/受控异常/受检异常:编写代码阶段就必须处理异常,否则编译不通过,所有的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、集合

  • 集合不能直接存储基本数据类型,其存储的是引用,即内存地址。
1 2
  • 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,代码:

posted on 2020-12-23 22:34  零_壹  阅读(83)  评论(0编辑  收藏  举报