JAVA基础知识的梳理,面试的小伙伴可以先复习一下。纯纯的八股文

1、对象转型

1、一个基类的引用类型变量可以“指向”其子类的对象;

2、一个基类的引用不可以访问其子类对象新增加的成员(属性和方法);

3、可以使用 “引用变量 instanceof 类名” 来判断该引用型变量所”指向“的对象是否属于该类或该类的子类;

4、子类的对象可以当做基类的对象来使用称为向上转型(upcasting),反之称为向下转型(downcasting)或强制转换。

ps:祥见马士兵—》第03章_面向对象—》p37

2、final关键字

1、final的变量的值不能够被改变(final的成员变量,final的局部变量(形参))

2、final的方法不能够被重写(final不能修饰构造方法 )

3、final的类不能够被继承

4、子类无法使用从父类继承的private修饰的成员变量(可以通过非private方法间接操作,如果父类提供了各种方法)

public class T {
    
    
	final int i; //报错,成员变量必须进行初始化,且声明与赋值操作必须在同一条语句中
	
	public void m(final int j) {
    
    
		j = 8; //报错,这样理解:j作为参数,在方法调用时的参数传值过程中进行首次赋值
	}
	
	public void f() {
    
    
		final int k;
		k = 9; //OK,局部变量的声明与赋值操作在两条语句中,不算final变量的重新赋值
	}
}

JDK中也有final类:String、 Math、 Boolean等

3、this与super关键字

1、this表示对当前对象的引用:

1)解决成员变量与局部变量的二义性;

2)调用当前类的构造方法,与参数列表相关;

3)调用普通方法;

4)this当作参数传递;

5)this当作返回值返回。

ps:this不能在静态方法中使用,只能在当前类中使用,在构造方法中使用this只能放在第一行

2、super:

1)调用超类的方法;

2)而是调用超类的构造器。

ps:在构造方法中使用super只能放在第一行。

super与this的区别:super不是一个对象的引用,不能将值super赋给另一个对象变量。它只是一个指示编译器调用超类方法的特殊关键字。

【注意】调用构造器的语句只能作为另一个构造器的第一条语句中出现。构造器参数可以传递给当前类(this)的另一个构造器,也可以传递给超类(super)的构造器。(因此this()和super()不能在同一构造方法中同时出现)

public class Animal {
    
    
	private String name;
	
	Animal(){
    
    	
	}
	
	Animal(String name){
    
    
		this.name = name;
	}
}

public class Person extends Animal{
    
    
	private int age;
	private String address;
	
	Person(String name, int age){
    
    
		this.age = age; //隐式调用super()
	}
	
	Person(String name, int age, String address){
    
    		
		super(name); //报错,可以理解为this(age)已经显式或隐式的调用了super方法
		this(age);
		this.address = address;
	}
}

4、lang常用类:String

1char charAt(int index)  //返回 index索引处的char字符
2boolean endsWith(String suffix)  //判断当前字符串是否以指定的后缀suffix结尾
3boolean startsWith(String prefix)  //判断当前字符串是否以指定的前缀prefix开头
4boolean isEmpty()  //当length()为0时返回true,否则false
5int length()  //返回此字符串的长度
6String toLowerCase()  //将此字符转换为全大写
7String toUpperCase()  //将此字符转换为全小写
8String substring(int beginIndex)  //从当前字符串中截取子串,子字符串以指定索引处的字符开头,并扩展到该字符串的末尾。 
9String substring(int beginIndex,int endIndex)  //从当前字符串中截取子串,子串的索引在beginIndex和endIndex-1之间,子串的长度为endIndex-beginIndex。
10int indexOf(String str)  //返回字符串中第一次出现str的索引,如果不存在返回-1
11int indexOf(String str, int fromIndex) //返回字符串从fromIndex开始,第一次出现str的索引
12boolean equalsIgnoreCase(String anotherString) // 在equals方法基础上,忽略大小写的比较
13public String replace(char oldChar, char newChar) //在字符串中用newChar替换全部oldChar
14String trim()  //  返回将该字符串去掉开头和结尾空格后的字符串
15String[] split(String regex) // 将一个字符串按照指定的分隔符分隔,返回分隔后的字符串数组
16static String valueOf(Object obj) //静态重载方法,参数列表有double d, int i...可以将基本数据类型或引用数据类型,转换成字符串类型
    
课堂补充:
public String concat(String str) //将指定的字符串拼接到该字符串的末尾
public boolean contains(CharSequence s) //是否包含某字符串,String类是CharSequence接口的实现类
public int lastIndexOf(String str) //返回指定子字符串最后一次出现的字符串中的索引
public String replace(char oldChar, char newChar) //替换元素
public char[] toCharArray() //将此字符串转换为新的字符数组
public static String valueOf(char[] data) //将char数组转换为String类型

5、StringBuilder 与 StringBuffer:

字符串分为:

不可变字符串:String

可变字符串:StringBuilder StringBuffer

StringBuilder:
构造方法:
    StringBuilder() //初始容量为16个字符
    StringBuilder(String str) //传递String创建对象,初始容量为16加上字符串参数的长度
    StringBuilder(int capacity) //指定初始容量
    StringBuilder(CharSequence seq) //初始容量为16加上CharSequence参数的长度
常用方法:
    public StringBuilder append(CharSequence s) //末尾拼接
    public int capacity() //返回当前容量
    public char charAt(int index) //索引指定位置的元素值
    public StringBuilder delete(int start, int end) //区间删除,end不含
    public StringBuilder insert(int dstOffset, CharSequence s) //在指定位置插入CharSequence
    public StringBuilder reverse() //反转字符串
    // ps:以上带StringBuilder返回值的方法,将原StringBuilder类型字符串进行修改,并将修改后的数据以StringBuilder类型返回。
    
//StringBuffer的方法与StringBuilder几乎一样。

区别:

1、StringBuilder:线程不安全,StringBuffer:线程安全;

2、StringBuilder从JDK1.5出现,StringBuffer从JDK1.0出现;

3、由于StringBuilder没有考虑同步,在单线程情况下,StringBuilder的性能要优于StringBuffer

4、底层都是基于char类型的数组,因此才能通过索引值访问里面的字符,例如方法:char charAt(int index)

5、String类型每次修改字符串都会创建新的对象,StringBuilder和StringBuffer底层数组在创建时确定大小,直到数组满了就会创建一个新的数组,并且指向这个数组的地址(自动扩容)。

String类型三种空的形式:
	String s1 = "";	 //空值,是指一个字符床对象已经实例化,即系统已经给该变量分配了空间,只是对象的内容为空;

	String s2 = new String();  //空对象,是指一个字符床对象已经实例化,即系统已经给该变量分配了空间,只是对象的内容为空;

	String s3 = null;  //空字符串,只定义一个对象s3,没有给该对象分配空间,即没有实例化该对象。因此,空对象在调用时候都会抛出异常;
String s1 = "abcd";
String s2 = "ab" + "cd";
String s3 = "abc";
String s4 = s3 + "d"; 
String s5 = new String("abcd");

System.out.println(s1 == s2); // true
System.out.println(s1 == s4); //false
System.out.println(s1 == s5); //false

1、凡是字符串,值都在常量池中,在创建的时候,会先去常量池看看是否存在,如果存在拿到地址值,如果不存在,创建一个新的;
2、s2在编译过程中会自动拼接完成这两个字符串,然后在常量池中寻找是否已有,否则创建新的;
3、s4编译过程为String s4 = new StringBuilder(s3).append("d")4、需结合内存图理解。

6、lang常用类:包装类

四类八种:Byte,Short,Character,Integer,Long,Float,Double,Boolean

常见用法,以java.lang.Integer为例:

属性

public static final int MAX_VALUE:最大的int型数 2 31 -1(int类型取值范围中的最大值)
public static final int MIN_VALUE:最大的int型数 -2 31

方法:

构造方法:
public Integer(int value)
public Integer(String s)
        throws NumberFormatException:调用可能抛出异常的构造方法在创建对象的时候,不需要捕获异常
    	因为它是运行时异常??
方法:
public long longValue()//返回封装数据的long型值
public double doubleValue()//返回封装数据的double型值
public int intValue()//返回封装数据的int型值
public byte byteValue()//返回封装数据的byte型值
//在基本数据类型的转换中会调用以上方法

static int parseInt(String s)
    		throws NumberFormatException
//将字符串解析成int型数据,返回该数据
    反之:String类的 public static String valueOf(int i)方法:返回int参数的字符串形式。
public static Integer valueOf(int i) //返回一个int值的Integer对象
public static Integer valueOf(String s)
                       throws NumberFormatException
//返回Integer对象,其中封装的整型数据为字符串s所表示
    
static String toString(int i) 转换为带符号的十进制字符串形式(toUnsignedString:有符号)
static String toHexString(int i)   转换为十六进制字符串形式
static String toBinaryString(int i)   转换为二进制字符串形式
static String toOctalString(int i)   转换为八进制字符串形式 

装箱与拆箱:装箱:将基本数据类型转换为包装类;拆箱:将包装类转换为基本数据类型

自动装箱:Integer i1 = 10; 
自动拆箱:int i2 = i1;
    
手动装箱:Integer i3 = new Integer(10);
手动拆箱:int i4 = i3.intValue();

享元模式:将byte类型的取值范围 (-128~127) 进行缓存(缓存:提前加载),只针对四种整型。

Integer i1 = 123;
Integer i2 = 123;

Integer i3 = new Integer(123);
Integer i4 = new Integer(123);

Integer i5 = 128;
Integer i6 = 128;

System.out.println(i1 == i2); //true (i1和i2同时指向缓存区中123的地址值)
System.out.println(i3 == i4); //false
System.out.println(i5 == i6); //false

7、lang常用类:Math

属性:
    public static final double E   //Math.E   2.718...  自然对数的底数(常数e)
    public static final double PI   //Math.PI  3.14...
方法:
    public static int abs(int a) //绝对值,(double, float, int, long)
    public static double log(double a) // 自然对数
    public static double exp(double a) // e为底的指数
    public static double pow(double a, double b) // a的b次幂
    public static double sqrt(double a) //平方根
    public static double max(double a, double b) //返回两个 double值中的较大值 
    public static double min(double a, double b) //返回两个 double值中的较小值
    public static long round(double a) // double型的数据a转换为long型(四舍五入)
    public static int round(float a) // float型的数据a转换为int型(四舍五入)
    public static double random() // 返回>=0.0, <1.0的随机数
    public static double toDegrees(double angrad) //弧度->角度
    public static double toRadians(double angdeg) //角度->弧度
    
    aco、asin、atan、cos、sin、tan:()正弦,()余弦,()正切

8、java.io.File

java.io.File类代表系统文件名(路径和文件名)。

常见构造方法:
    public File(String pathname) //以pathname为路径创建File对象
    public File(String parent, String child) //以parent为父路径,child为子路径创建File对象
    
静态属性:public static final String separator //当前系统的路径分隔符。
    
常用方法:
1、通过File对象可以访问文件的属性:
    public boolean canRead()
    public boolean canWrite()
    public boolean exists()
    public boolean isDirectory()
    public boolean isFile()
    public boolean isHidden()
    public long lastModified()
    public long length() //返回由此路径名表示的文件的长度(以字节为单位)
    public String getName()
    public String getPath()
    public String getAbsolutePath()
    public File[] listFiles() //返回一个File对象的数组,由该抽象路径名表示的每个文件或目录
2、通过File对象创建空文件或目录(在该对象所指的问价或目录不存下的情况下):
    public boolean createNewFile() throws IOException
    public boolean delete()
    public boolean mkdir()
    public boolean mkdirs() //创建在路径中的一系列目录
【案例】递归列出文件目录结构
package cn.itsource.test6;

import java.io.File;

public class FileList {
    
    
	public static void main(String[] args) {
    
    
		File f = new File("C:/Users/54642/Desktop/JAVA");
		System.out.println(f.getName());
		tree(f, 1);
	}
	
	public static void tree(File f, int level){
    
    
		String preStr = "";
		for (int i = 0; i < level; i++) {
    
    
			preStr += " "; //文件目录按结构层次缩进处理
		}
		
		File[] childs = f.listFiles(); 
		for (int i = 0; i < childs.length; i++) {
    
    
			System.out.println(preStr + childs[i].getName());
			if(childs[i].isDirectory()){
    
    
				tree(childs[i], level + 1); //方法的递归调用
			}
		}
	}
}

9、异常

java.lang.Throwable
    Exception
    	运行时异常-RuntimeException ()
    	非运行时异常 (包括IOException)
    Error

Throwable类是Java语言中所有错误和异常的父类;
Error类称为错误,由Java虚拟机生成并抛出,包括内存溢出、动态链接失败,虚拟机错误等,程序无法解决;
Exception是所有异常类的父类;
RuntimeException:包括IndexOutOfBoundsExceptionArithmeticException异常,其产生比较繁琐,处理麻烦,如果显示的声明或捕获将会对程序可续性和运行效率影响很大,因此由系统自动检测并将他们交给缺省的异常处理程序(用户可不必对其处理)。

非运行时异常:在编译的期间,就会有提示

运行时异常:程序在运行的过程中出现的异常

异常:运行期间出现的错误(观察错误的名字和行号)

1、Java异常是Java提供的用于处理程序中错误的一种机制。

2、所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。

3、设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。

4、Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被提交给Java运行时系统,这个过程称为抛出(throw)异常。

5、当Java运行时系统接受到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程成为捕获(catch)异常。

try{…}catch(…){…},

声明方法中throws的异常(且非runtime exception), 必须对其进行捕捉(try…catch…)

throws:抛出异常
    是写在方法的参数列表之后,每个异常逗号隔开
    
throw:调用异常
    写在逻辑代码中的,一次只能调用一个异常类

catch语句:在catch语句块中是对异常进行处理的代码,如:打印异常信息、记录异常到日志文件、抛出异常等,可以使用异常对象的一些方法获取这些信息,例如:printStackTrace()方法,getMessage()方法。

finally语句:通常在finally语句中执行资源的清除工作(关闭打开的文件,删除临时文件等)

public static void main(String[] args) {
    
    
    try{
    
    
        System.out.println("有可能出现异常的代码");
        return;	
    }catch(ArithmeticException e){
    
    
        System.out.println("提示异常信息");;
    }finally{
    
    
        System.out.println("无论是否出现异常都会执行!!!");
    }
    System.out.println("111111111");		
}

finally里面的代码块在正常情况下放在try...catch语句外面也会被执行;
但是如果在try语句里面有return语句,则finally代码块仍然会执行,外面则不会被执行;
只有在遇到System.exit(0)语句时,finally才不会被执行(PS:System.exit(0)表示虚拟机关闭)

在多异常处理中,必须先捕获子类异常,后捕获父类异常或Exception,通常Exception放在最后进行兜底;

自定义异常:

1、继承Exception;

2、添加无参与有参的构造方法;

3、在方法体中生成自定义异常的实例,并用throw 语句抛出, 一次只能抛出一个异常;

4、在方法声明部分,参数列表的后面用throws语句声明该方法可能抛出的异常,可以是多个异常逗号隔开。

自定义异常:代码演示
public class Test {
    
    
	String[] names = {
    
    "Jay", "Edson", "Tracy", "Wendy"};
	public static void main(String[] args) {
    
    
		Test t = new Test();
		try {
    
    
			t.register("Jay");
		} catch (EmptyException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExistException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void register(String name) throws EmptyException, ExistException{
    
    
		if(name == null | name == ""){
    
    
			throw new EmptyException("用户名不能为空");
		}
	
		for (String string : names) {
    
    
			if (string.equals(name)){
    
    
				throw new ExistException("用户已存在");
			}
		}
		System.out.println("注册成功");
	}	
}

public class EmptyException extends Exception{
    
    	
	public EmptyException(){
    
    		
	}
	
	public EmptyException(String message){
    
    
		super(message);
	}
}

public class ExistException extends Exception {
    
    
	public ExistException(){
    
    		
	}
	
	public ExistException(String message){
    
    
		super(message);
	}
}

10、枚举类型

1、字段之间用逗号,最后一个字段用分号结束,可以写中文字段,但是不建议;

2、枚举中全局常量类似于实例对象

3、枚举类默认隐式继承Enum类,其中toString方法返回枚举常量名的字符串形式

4、构造方法可以省略修饰符,默认是private的,不能用public、protected修饰

5、枚举类编译完毕也同样生成字节码文件

//枚举创建方式1:
enum Gender1{
    
    
	MAN, WOMEN, UNKNOWN
}

//枚举创建方式2:
enum Gender2{
    
    
	MAN("男"), WOMEN("女"), UNKNOWN("未知");
	
	private String name;
	
	Gender2(){
    
    
		
	}
	
	Gender2(String name){
    
    
		this.name = name;
	}
	
	@Override
	public String toString(){
    
    
		return name;
	}

}

11、线程

进程:正在运行的程序,是一个静态的概念,在系统中实际运行的都是线程

线程:是进程中最小的单位,每个进程最少有一个线程,是一个程序里面不同的执行路径(一个程序内部的顺序控制流)

多进程:在操作系统中能同时运行多个任务(程序)

多线程:在同一应用程序中有多个顺序流同时执行

cpu眼里只有线程,没有进程的概念。线程会争抢cpu的执行权,抢占式调度系统

实现多线程的两种方式:

一、继承Thread类:1继承Thread;2重写run方法;3创建自定义的线程对象;4调用start方法启动线程

二、实现Runnable接口:1实现Runnable接口;2重写run方法;3创建实现类对象;4创建Thread类对象 Thread(Runnable target, String name) ;5调用start方法启动线程

继承Thread:只要继承了,自己就是一个线程类;每创建一个自定义的线程对象,都是一个新的线程。

实现Runnable:实现了Runnable接口,只是拥有的线程的功能,但是不能启动线程;必须依赖于Thread才能启动线程。

1、Thread类是Runnable接口的已知实现类;

2、多线程中,使用继承Thread方法,每个线程都要创建一个(线程子类)对象;而使用实现Runnable方法,只需创建一个(实现类)对象,然后针对每个线程创建一个Thread类对象。

3、买票案例中:继承Thread情况下,票数num需为static修饰(多个线程子类的对象共享50张票);而实现Runnable情况下,num不需要static修饰,因为只创建了一个实现类对象。

4、直接调用run方法只会在同一个线程中执行这个任务,而没有启动新的线程。应当调用Thread.start方法,这会创建一个执行run方法的新线程。

5、继承Thread方法,只能单继承;实现Runnable接口,还可以继承其他类并实现多个接口。

main方法是主线程,主线程启动了子线程,但是主线程结束了并不意味着子线程也会结束

设置线程的名字:1.通过构造方法 super(name);2.通过setName方法

获取线程的名字:1.getName() //此方法不推荐,在实现接口的情况下无法使用;

​ 2.Thread.currentThread().getName() //推荐

多线程案例:火车站售票案例(出现线程不安全的问题)

Thread类的休眠暂停方法:public static void sleep(long millis) throws InterruptedException

使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),调用该方法可能抛出InterruptedException异常,需捕获或抛出。

解决线程安全问题(三种方式):

1、同步代码块:synchronized (类名.class) { … } //括号中的类名.class是为了保证是同一把钥匙

2、同步方法(最不推荐,最好不用):创建static synchronized修饰的方法,并通过run方法调用该方法

3、Lock锁(常用): static Lock lock = new ReentrantLock();(需导包) lock.lock(); lock.unlock();

以上方法的重点在于:1两次循环判断;2保证是同一把钥匙(this是默认的钥匙,每个对象都有一把,不能用)

并且不推荐同步方法,因为静态方法存在特殊意义,会被jvm优先加载,一般不会自己创建。

12、正则表达式

正则表达式用于校验字符串是否满足一定的规则

使用场景:注册页面、eclipse中的搜索和替换功能(Ctrl + f)

实际使用中可以在线百度:正则表达式生成器

String类中的方法:

public boolean matches(String regex):用于判断此字符串是否匹配给定的regex正则表达式。

记住四个例子:邮政编码、手机号、邮箱、身份证号

常见的正则表达式语法格式:
  	ABC--->匹配你输入字符是否是ABC
 	[0-9]-->只能匹配一个字符,看你输入的单个字符是否是数字
  	[0123456789]-->和上面是一样的意思
  	\d---->和上面表示同一个意思
  	[a-z]-->只能匹配一个字符,看你输入的单个字符是否是英文的并且是小写
  	[a-zA-Z]-->只能匹配一个字符,看你输入的单个字符是否是英文字母的
  	[a-zA-Z0-9]-->只能匹配一个字符,看你输入的单个字符是否是英文或者数字
  
	 . 任何字符(与行结束符可能匹配也可能不匹配) 
	\d 数字:[0-9] 
	\D 非数字: [^0-9] 
	\s 空白字符:[ \t\n\x0B\f\r] 
	\S 非空白字符:[^\s] 
	\w 单词字符:[a-zA-Z_0-9] 
	\W 非单词字符:[^\w] 

边界匹配器 
	^ 行的开头 
	$ 行的结尾 

Greedy 数量词 
	X?  X,一次或一次也没有 
	X*  X,零次或多次 
	X+  X,一次或多次 
	X{
    
    n}  X,恰好 n 次 
	X{
    
    n,}  X,至少 n 次 
	X{
    
    n,m}  X,至少 n 次,但是不超过 m 次 
		
Logical 运算符 
	XYX 后跟 Y 
	X|YXY 

13、常用快捷键

win+E:快速打开我的电脑
DOS命令: notepad打开记事本
运行:ctr+F11 
ctrl+1:创建新的数据类型及变量名
Ctrl+D:删除整行
win+v:打开剪切板
Ctrl+Shift+A:列编辑快捷键
Ctrl+E:切换编辑窗口
Ctrl+Shift+/右:选中光标所在位置左/右的一个单词,可连续向左/右移动

 * 	代码提示:alt+/ (m:main方法,syso:打印方法)
 * 	单行注释:ctrl+/ 
 * 	多行注释:ctrl+shift+/ (撤销多行注释:ctrl+shift+\)
 * 	文档注释:shift+alt+j
 * 	移动代码:alt+上下
 *  快速复制:ctrl+alt+上下
 *  整理代码:ctrl+shift+f
 *  右键source: alt+shift+s  r(get与set)  o(有参构造)  c(无参构造)  s(toString)
 *  查看当前类的元素:ctrl+o
 *  快速导包:ctrl+shift+o (同时删除已导入但未使用的包)
 *  快速查找类:ctrl+shift+t
 *  查找替换:ctrl+f (勾选ScopeSelected lines,可以对选定的行进行全部替换)
 *  快速替换:alt+shift+r
 *  代码放大缩小:alt+shift+a
 *  代码放大缩小: Ctr +/-

14、Timer定时器

构造方法::Timer() 
    
常用方法:
    public void schedule(TimerTask task, Date time)
    public void schedule(TimerTask task, Date firstTime, long period)
    public void schedule(TimerTask task, long delay)
    public void schedule(TimerTask task, long delay, long period)
    public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
    public void scheduleAtFixedRate(TimerTask task, long delay, long period)
    
参数:    
    task - 要执行的任务
    time - 执行任务的时间
    firstTime - 第一次执行任务
    delay - 执行任务之前以delay为单位的延迟
    period - 连续执行任务之间的毫秒数。

TimerTask :抽象类,其中包含抽象方法run(),可通过匿名内部类方式重写run()方法创建对象,并将其作为参数传入Timer类的方法中。

//public void schedule(TimerTask task, Date time) 在指定的时间安排指定的任务执行
String time = "2022-05-17 13:53:00";
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = sf.parse(time);
t.schedule(new TimerTask() {
    
    
	@Override
	public void run() {
    
    
		System.out.println("兄弟上路了!改日在见!!!");
	}
}, parse);

//void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
String time = "2021-11-29 09:12:00";
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = sf.parse(time);
t.scheduleAtFixedRate(new TimerTask() {
    
    
	@Override
	public void run() {
    
    
		System.out.println("你看看我有什么不一样");
	}
}, parse, 1000);

15、BigDecimal、System、Runtime、垃圾回收

1、BigDecimal(与运算相关的类)

构造方法:public BigDecimal(String val)
常用方法:
    public BigDecimal add(BigDecimal augend)  // 加法
    public BigDecimal subtract(BigDecimal subtrahend)  // 减法
    public BigDecimal multiply(BigDecimal multiplicand)  // 乘法
    public BigDecimal divide(BigDecimal divisor)
    		// 除法(如果除不尽,则抛出ArithmeticException异常)
    public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
    		// 除法(常用) : scale保留小数位数;roundingMode舍入模式,常用RoundingMode.HALF_UP   

2、System(无构造方法,不能被实例化)

常用方法:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)  //将指定源数组中的数组从指定位置复制到目标数组的指定位置。缺点:必须事先创建参数 dest 指定的数组
        参数:    
            src - 源数组。 
            srcPos - 源数组中的起始位置。 
            dest - 目标数组。 
            destPos - 目标数组中的起始位置。 
            length - 要复制的数组元素的数量。
    
public static long currentTimeMillis() //返回当前时间毫秒数的long类型,当前时间距离1970年1月1日

3、Runtime:运行时

public static Runtime getRuntime() //返回与当前Java应用程序关联的运行时对象
public Process exec(String command) throws IOException //在单独的进程中执行指定的字符串命令
    
Runtime r = Runtime.getRuntime(); //获取运行时对象
r.exec("mspaint"); //运行画图工具
r.exec("jd-gui"); //jd-gui.exe文件需在 C:\Windows\System32 路径下
r.exec("C:\\Users\\54642\\Desktop\\JAVA\\软件\\java反编译软件\\jd-gui");
ps:1只能打开exe文件,2未指定文件路径时,需将该exe文件置于C:\Windows\System32路径下

4、垃圾回收机制:

System类:
    public static void gc() //运行垃圾回收器
Object类:
    protected void finalize() throws Throwable //
上述二者之间有关联。
    
代码演示(回收情况是不可控的)public class TestPerson {
    
    	
	public static void main(String[] args) {
    
    
		for (int i = 0; i < 10; i++) {
    
    
			new Person();
		}		
		System.gc();
	}
}

public class Person {
    
    	
	@Override
	protected void finalize() throws Throwable {
    
    
		System.out.println("当前对象被回收了");		
	}
}

16、随机数及验证码

1Math类:
    public static double random() //返回double类型的值为正号,大于等于0.0 ,小于1.0
    // Math.random()*(end-begin)+begin:表示begin到end之间的随机数
    
2Random类:
	public int nextInt() //int类型取值范围的随机数,包含了负数
    public int nextInt(int bound) //随机范围在0<=num<bound
    
3ThreadLocalRandom类:
    public static ThreadLocalRandom current() //返回当前线程的 ThreadLocalRandom对象
    public int nextInt(int origin, int bound) //随机范围origin(含)到bound(不含)之间

4UUID类:
    public static UUID randomUUID() //产生的随机数类似这种格式:26c6ac96-7dd4-4f67-8b21-bb224c026c3f,以前有在数据库中作为主键使用,现在几乎不用了

验证码案例:

String code = "njvdug是你的呢欧iauwet4387yt6q%&*(T一天hirgbvbenigu而我国发你";
Random r =new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 4; i++) {
    
    
    int index = r.nextInt(code.length());
    char c  = code.charAt(index);
    sb.append(c);
}
System.out.println("验证码为:" + sb.toString());

17、时间、格式、日历

Date(导包:import java.util.Date):
    构造方法:
    Date() //获取当前时间对象
    Date(long date) //根据毫秒数设置时间
    常用方法:
    public boolean before(Date when) //测试此日期是否在指定日期之前
    public boolean after(Date when) //测试此日期是否在指定日期之后

代码演示:
Date d1 = new Date(); //创建当前时间对象
System.out.println(d1); //Tue May 17 20:26:26 CST 2022

long ct = System.currentTimeMillis();
long yt = ct - 24*60*60*1000; //1970.1.1 到昨天这个时候的毫秒数
System.out.println(yt); //1652703986579

Date d2 = new Date(yt); //创建昨天这个时间对象
System.out.println(d2); //Mon May 16 20:26:26 CST 2022

boolean b1 = d2.before(d1);
System.out.println(b1); //true

boolean b2 = d2.after(d1);
System.out.println(b2); //false
SimpleDateFormat (导包:import java.text.SimpleDateFormat):格式化时间的类
    构造方法:
    public SimpleDateFormat(String pattern) //根据指定的格式  格式化时间
    常用方法:
    DateFormat类中的方法 (SimpleDateFormat 继承 DateFormat)public final String format(Date date) //将时间转换为指定的格式  并且以字符串的形式返回
    	public Date parse(String source) throws ParseException //将字符串的时间转换为Date类型
              的时间,需导包:import java.text.ParseException,并捕获或抛出ParseException异常。
    
代码演示:
    
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatTest {
    
    	
	public static void main(String[] args) throws ParseException {
    
    
		Date d1 = new Date();
		System.out.println(d1);
		
		SimpleDateFormat sf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String s1 = sf1.format(d1);
		System.out.println(s1);
		
		SimpleDateFormat sf2 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 E");
		String s2 = sf2.format(d1);
		System.out.println(s2);
		
		SimpleDateFormat sf3 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
		String s3 = sf3.format(d1);
		Date d2 = sf3.parse(s3);
		System.out.println(d2);
	}
}
Calendar (导包:import java.util.Calendar):
    构造方法:protected修饰无法使用
    常用方法:
    static Calendar getInstance() //获取日历对象
    void set(int field, int value) //将给定的日历字段设置为给定的值
    Date getTime() //返回时间
    int get(int field) //返回给定日历字段的值
    void setTime(Date date) //设置时间
    abstract void add(int field, int amount) //将amount指定的时间量添加或减去给定的日历字段
    
代码演示:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class CalendarTest {
    
    	
	public static void main(String[] args) {
    
    
		Calendar c1 = Calendar.getInstance(); //获取日历对象
		c1.set(Calendar.YEAR, 1991);
		c1.set(Calendar.MONTH, 7); // 0~11,0表示1月
		c1.set(Calendar.DAY_OF_MONTH, 22);
		Date time = c1.getTime();
		System.out.println(time); //Thu Aug 22 21:49:38 CDT 1991
		
		SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 E");
		String s = sf.format(time);
		System.out.println(s); //1991年08月22日 21时49分38秒 星期四
		
		Date d = new Date();
		System.out.println(d); //Tue May 17 21:49:38 CST 2022
		Calendar c2 = Calendar.getInstance();
		c2.setTime(d); 
		int y = c2.get(Calendar.YEAR);
		System.out.println(y); //2022
		int m1 = c2.get(Calendar.MONTH);
		System.out.println(m1); //4
		
		c2.add(Calendar.MONTH, 1);
		int m2 = c2.get(Calendar.MONTH);
		System.out.println(m2); //5
		
		int day = c2.get(Calendar.DAY_OF_MONTH);
		System.out.println(day); //17		
	}
}

【注意】直接打印:System.out.println(Calendar.DAY_OF_MONTH),不准确!!!

18、数据结构

数据结构定义: 计算机对数据存储的一种安排;数据结构是对数据进行组织和管理。

1、基于数组的结构(ArrayList):

​ 优点:查询与修改性能高;缺点:添加与删除性能低

2、基于链表的结构(LinkedList):与数组正好相反

1、基于数组的结构
import java.util.Arrays;
public class IntegerList {
    
    	
	private Object[] value;	
	int count = 0;
	
	public IntegerList(){
    
    
		this(10); //设置自定义数组长度为10
	}
	
	public IntegerList(int capacity){
    
    
		value = new Object[capacity];
	}
	
	public void add(Object num){
    
    
		if (value.length <= count){
    
    
			Object[] newArr = new Object[value.length * 2]; //扩容两倍
			System.arraycopy(value, 0, newArr, 0, value.length);
			value = newArr;
		}
		value[count] = num;
		count++;
	}

	public String toString(){
    
    
		Object[] newArr = new Object[count];
		System.arraycopy(value, 0, newArr, 0, count);
		return Arrays.toString(newArr);
	}
	
	public int length(){
    
    
		return count;
	}
	
	public Object getIndexValue(int index){
    
    
		if(index >= 0 && index < value.length){
    
    
			return value[index];
		}
		return -1;
	}
	
	public void delete(int index){
    
    
		if(index >= 0 && index < value.length){
    
    
			System.arraycopy(value, index+1, value, index, value.length-index-1);
			count--;
		}
	}
}
2、基于链表的结构
public class Node {
    
    	
	Object value;
	Node node;
	
	public Node(Object value) {
    
    
		this.value = value;
	}			
}

public class LinkedListTest {
    
    	
	Node firstNode;
    Node lastNode;
	int count = 0;
	
	public void add(Object obj){
    
    
		Node node = new Node(obj);
		
		if (firstNode == null){
    
    
			firstNode = node;
		}else{
    
    
			lastNode.node = node;
		}
		lastNode = node;
		count++;
	}
	
	public int getSize(){
    
    
		return count;
	}

	@Override
	public String toString(){
    
    
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		Node n = firstNode;
		while (n != null){
    
    
			sb.append(n.value);			
			if (n.node != null){
    
    
				sb.append(",");				
			}
			n = n.node;
			if (n != null){
    
    
				sb.append(" ");				
			}
		}
		sb.append("]");
		return sb.toString();
	}
}

19、List集合和Set集合

集合:存储任意类型任意属性的元素
Collection(接口)
    List(接口):可以存储重复的元素,存取有序;
    	ArrayList(常用):底层基于数组的结构(查询与修改性能高,添加与删除性能低)
    	LinkedList:底层基于链表结构(与数组正好相反)
    Set(接口):不能存储重复元素,存取无序;
        HashSet(常用):
            底层存储方式:JDK1.8 哈希表=数组+链表+红黑树 (当链表长度超过8的时候使用红黑树)
		TreeSet
ArrayList:
    构造方法:
    ArrayList() //构造一个初始容量为10的空列表。
    	List l = new ArrayList(); //以多态的方式创建
		ArrayList list = new ArrayList();
    ArrayList(Collection<? extends E> c) //根据集合创建集合对象
    ArrayList(int initialCapacity) //构造具有指定初始容量的空列表。
    
    常用方法:
        boolean add(E e) //将指定的元素追加到末尾。
        void add(int index, E element) //在此列表中的指定位置插入指定的元素。 
        boolean addAll(Collection<? extends E> c) //将集合对象新增到当前集合中
        boolean addAll(int index, Collection<? extends E> c) //在指定位置插入集合
        
        boolean contains(Object o)  //判断此元素是否存在
        E get(int index) //根据索引返回指定元素
        int indexOf(Object o)   //查找元素第一次出现的位置
        int lastIndexOf(Object o)   //最后一次出现的位置
        E remove(int index)  //删除指定位置的元素
        boolean remove(Object o)   //删除指定的元素
        int size()   //元素个数
        Object[] toArray()   //集合转换为数组
        void clear()   //清空元素
        
PS:remove方法中,如果删除的元素是整型或字符型,要使用 new Integer(123)new Character('g')方式,以免和索引号冲突
LinkedList:
    构造方法:
    LinkedList() //链表结构不需要指定容量
    LinkedList(Collection<? extends E> c) 
    常用方法:
        void addFirst(E e)  在头部添加元素
        void addLast(E e)   在末尾处添加元素
        E element()  检索但不删除第一个元素
        E getFirst()   返回第一个元素
        boolean offerFirst(E e)   前面插入元素
        E removeFirst()  删除并且返回第一个元素
集合遍历的三种方式:
    for循环:调用size和get方法;
    增强for循环:Object类变量来接收集合中的元素;
    迭代器:通过调用hasNext()方法判断,next()方法获取。(多态,Iterator<E>是一个接口)
    	iterator方法(ArrayList)
    	listIterator(LinkedList)    		
    	//如果迭代没有更多的元素,继续调用next()方法,会抛出NoSuchElementException异常
PS1LinkedList的大部分方法与ArrayList一致
    2、由于LinkedList实现了Deque<E>Queue<E>接口,因此拥有了很多头尾操作的方法
    3ArrayListLinkedList都实现了Iterable<T>接口,实现此接口允许对象成为“for-each”语句的目标
HashSet:
    构造方法:
    HashSet() //默认初始容量(16)和负载因子(0.75)
    HashSet(Collection<? extends E> c) 
    HashSet(int initialCapacity) //指定初始容量和默认负载因子(0.75)
    HashSet(int initialCapacity, float loadFactor) //指定初始容量和指定负载因子
    常用方法:
    boolean add(E e)  
    void clear()  
    boolean contains(Object o) 
    boolean remove(Object o)  
    int size()  
    Iterator<E> iterator()  

遍历HashSet1、增强for循环 //HashSet同样实现了Iterable<T>接口
    2、迭代器
    
PS1、负载因子(load factor)可以确定何时对散列表进行再散列。例如,如果负载因子为0.75(默认值),说明表中已经填满了75%以上,就会自动再散列,即扩容;
    2、如何判断重复的元素:通过比较添加进去的元素的 hashCode 和 eqauls,如果两者的hashcode不一致那么不会再进行比较,如果两者的hashcode一致那么会继续对比属性值是否相等,如果两个对象的hashCode相等,并且两个对象调用equals结果是true,才认为两个元素重复。
    3、由于HashSet存取无序,因此不存在索引值,没有关于利用索引进行操作的方法存在;
    4HashSet没有get方法,不能使用for循环遍历;
    5、针对引用数据类型的元素,如果不想添加属性相同的两个元素,需重写hashCode和equals方法(自动覆写);		hashCode是通过属性计算哈希值;
    6、如果既要重写hashCode和equals方法,又想添加重复元素,可以在hashCode方法的result计算式里面            +new Random().nextInt()7、由于add(E e)中要求传入的参数类型E是引用数据类型,因此当传入基本数据类型时会转换成包装类(自动装箱)
    
Set set = new HashSet();
set.add(1); 由于自动装箱规则,这里的1会转换成Integer包装类
set.add("1");
set.add(new Integer(1)); //与第一次添加元素重复,因此不会添加进来	
System.out.println(set); //[1, 1]
TreeSet:
【特点】:
    1、无序 (意思是;不保证(不记录)添加的顺序)
    2、不重复 (多个心眼?)
    3、内部进行了排序
    4、元素的数据类型一致
【注意】:
    1TreeSet一旦添加了第一个元素后就不能添加其它数据类型的元素了,只能添加相同数据类型的元素,除非将容器中所有的元素全部清空,才能添加新的数据类型的元素;
    2、插入到集合中的所有元素必须实现Comparable接口,相互之间可比较;
    3、add方法同样涉及自动装箱;
    
构造方法:
TreeSet() //元素必须实现Comparable接口,并重写compareTo方法
TreeSet(Comparator<? super E> comparator)//使用匿名内部类方式传递比较器创建对象 并重写compare方法
常用方法:boolean add(E e) //新增

代码演示:
//方式一:实现Comparable接口,并重写compareTo方法
public class TestComparable {
    
    
	public static void main(String[] args) {
    
    
		TreeSet set = new TreeSet();
		set.add(new Person("周斯露",22));
		set.add(new Person("佺大哥",21));
		set.add(new Person("巴菲特老哥",21));
		set.add(new Person("曹银海老贼2",43));
		set.add(new Person("曹银海老贼1",43));
		set.add(new Person("高昂老哥哥你好帅欧耶",3));		
		System.out.println(set);
	}
}

public class Person implements Comparable{
    
    	
	private String name;
	private Integer age;
	public Person() {
    
    
	}
	public Person(String name, Integer age) {
    
    
		this.name = name;
		this.age = age;
	}
	public String getName() {
    
    
		return name;
	}
	public void setName(String name) {
    
    
		this.name = name;
	}
	public Integer getAge() {
    
    
		return age;
	}
	public void setAge(Integer age) {
    
    
		this.age = age;
	}	
	@Override
	public String toString() {
    
    
		return "Person [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int compareTo(Object o) {
    
    
		Person p1 = this;
		Person p2 = (Person)o;
		int value =p1.age.compareTo(p2.age);
		if(value == 0){
    
    
			value = p1.name.length() - p2.name.length();
			if(value == 0){
    
    
				value = p1.name.compareTo(p2.name);
			}			
		}
		return value;
	}
}

//使用匿名内部类方式传递比较器创建对象 并重写compare方法
import java.util.Comparator;
import java.util.TreeSet;
public class TestComparator {
    
    	
	public static void main(String[] args) {
    
    
		TreeSet set = new TreeSet(new Comparator() {
    
    
			@Override
			public int compare(Object o1, Object o2) {
    
    
				Student s1 = (Student)o1;
				Student s2 = (Student)o2;
				int value =s1.getAge().compareTo(s2.getAge());
				if(value == 0){
    
    
					value = s1.getName().length() - s2.getName().length();
					if(value == 0){
    
    
						value = s1.getName().compareTo(s2.getName());
					}			
				}
				return value;
			}
		});		
		set.add(new Student("周斯露",22));
		set.add(new Student("佺大哥",21));
		set.add(new Student("巴菲特老哥",21));
		set.add(new Student("曹银海老贼2",43));
		set.add(new Student("曹银海老贼1",43));
		set.add(new Student("高昂老哥哥你好帅欧耶",3));		
		System.out.println(set);		
	}
}

public class Student {
    
    	
	private String name;
	private Integer age;
	public Student() {
    
    
	}
	public Student(String name, Integer age) {
    
    
		this.name = name;
		this.age = age;
	}
	public String getName() {
    
    
		return name;
	}
	public void setName(String name) {
    
    
		this.name = name;
	}
	public Integer getAge() {
    
    
		return age;
	}
	public void setAge(Integer age) {
    
    
		this.age = age;
	}
	@Override
	public String toString() {
    
    
		return "Student [name=" + name + ", age=" + age + "]";
	}	
}

20、Map和泛型

Map(接口)HashMap(常用)JDK1.2  线程不安全  HashMap是用来替代HashTableHashTableJDK1.0  线程安全
    TreeMap:key具有自然排序能力,或者TreeMap中提供一个比较器 (不常用)
    LinkedHashMap:内部维护了一个链表,确保存取有序 (不常用)
    
HashMap(底层:数组、链表、红黑树)
特点:
    1、存储键值对
    2、键不能重复,值可以重复
    3、如果键重复,后面的值覆盖之前的值
构造方法:
    HashMap() //初始容量(16)和默认负载系数(0.75)
    HashMap(int initialCapacity) //指定的初始容量和默认负载系数(0.75)
    HashMap(Map<? extends K,? extends V> m) //根据Map创建HashMap对象
常用方法:
    V put(K key, V value) //添加元素 (key或者value都可以为null),如果添加的元素键重复,则返回被替换的值,如果不重复则返回null
    void putAll(Map<? extends K,? extends V> m) //添加Map
    boolean containsKey(Object key) //判断key值是否存在
    boolean containsValue(Object value) //判断value值是否存在
    V get(Object key) //根据key获取value值(如果key对应的value值为null或者key值不存在,都返回null)
    boolean isEmpty() //判断是否为空
    V remove(Object key) //根据key删除元素
    int size() //返回键值对数量
    void clear() //清空
遍历方法:
    Set<K> keySet() //获取所有的key,使用增强for循环遍历
    Collection<V> values() //获取所有的value,使用Collection类型接收并调用toArray()方法转换成数组,最后漂亮打印出来
    Set<Map.Entry<K,V>> entrySet() //返回包含Entry对象的Set集合,使用增强for循环,然后用Entry进行类型转换后调用getKey()和getValue()方法
    
Collections工具类:
    1ArrayListLinkedListTreeSetHashSetHashMap都是线程不安全的,调用Collections中的方法(如:static <T> Collection<T> synchronizedCollection(Collection<T> c))可以使集合变为线程安全的(基本上不用);   
常用方法:
    static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 			//返回集合中最大值
    static <T extends Comparable<? super T>> void sort(List<T> list) //自然排序
	static <T> void sort(List<T> list, Comparator<? super T> c) //自定义排序,匿名内部类  
   
Arrays类中的方法:static <T> List<T> asList(T... a)  可以返回由指定数组支持的固定大小的列表
    
Properties继承自Hashtable1、表示一个持久的属性集,用于读写资源文件(配置文件),一般是固定不变的内容;
    2、放入Properties中的key-value都是String类型;
    3、针对于第二点Properties中提供了特殊的存值和取值的方法,尽量不要用父类中的方法。
构造方法:
    Properties() //创建一个没有默认值的空属性列表
常用方法:
    Object setProperty(String key, String value) //新增
    String getProperty(String key) //根据key获取属性值
    String getProperty(String key, String defaultValue) //根据key获取属性值,如不存在使用默认值
    
    以后会使用IO流来进行文件读取:
    void list(PrintStream out) // 输出流(将内存中的数据写入到硬盘中)
    void load(InputStream inStream) // 输入流(将硬盘中的数据读取到内存中)
代码演示:
Properties pp = new Properties();
pp.setProperty("XXXX", "OOOO");
pp.setProperty("YYYY", "JJJJ");

PrintStream ps = new PrintStream("F:/qq.txt");
pp.list(ps);

FileInputStream fis = new FileInputStream("D:/eclipse-jee-juno-SR2-win32x86_64/eclipse/dropins/easyexplore.link");
pp.load(fis);
System.out.println(pp);
		
String property = pp.getProperty("path");
System.out.println(property);
泛型: 
    1Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法;
    2、就是一种规范,规定了对象与集合的类型;
    3、使用泛型的方法或实例化泛型的类,只能用传入引用数据类型,不能传入基本数据类型;
例如:
List<String> list = new ArrayList<String>();
Set<Integer> set = new HashSet<Integer>();
Map<String, Integer> map = new HashMap<String, Integer>();

泛型的作用:在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
泛型使用的地方:类、接口、方法、集合;

泛型的上限与下限:
	? : 表示通配符,不确定的类型,可以表示任意类型;
		? extends Number: 表示通配符?[上限],必须是NumberNumber的子类;
		? super Number: 表示通配符?[下限],必须是NumberNumber的父类;

类型变量:类型变量通常使用大写字母,且简短。Java库使用变量E表示集合的元素类型,KV分别表示键和值的类型,T表示任意类型。
	EElement 元素
	TType 类型
	KKeyVValue 值
    
泛型类:就是有一个或多个类型变量的类,
    1、类型变量在整个类定义中用于指定方法的返回类型以及字段和局部变量的类型;	
    
泛型方法:
    1、类型变量放在修饰符(public static)的后面,并在返回类型的前面;
    2、泛型方法可以在普通类中定义,也可以在泛型类中定义;
    3、当调用一个泛型方法时,可以把具体类型包围在尖括号中,放在方法名前面,也可以省略,编译器会自动进行类型推导;

泛型的方法:用泛型类型表示数组的时候,用T,不要用T[]

猜你喜欢

转载自blog.csdn.net/Libigtong/article/details/134289027
今日推荐