Java学习纪要

本文全面概述Java编程的基础知识,包括源文件规则、数据类型、运算符、控制结构、数组、面向对象概念如类、对象、构造器、继承、多态、抽象类与接口,以及异常处理、集合框架、泛型、枚举、注解、输入输出流、多线程、反射机制和动态代理等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

day01:

1.一个源文件(.java)中最多只能有一个声明为public的类,其他类的个数不限,如果源文件包含一个public类,则同时要求此类的类名与源文件名保持一致。
2.执行程序步骤:①编译:javac.exe(编译完会生成相应个.class字节码文件);②运行:java.exe
3.java的整型常量默认为int型,声明long型常量须后加‘l’或‘L’。
4.java的浮点型常量默认为double型,声明float型常量,须后加‘f’或‘F’。

day02

1.当char\byte\short之间运算时,默认的结果为int型。
2.字符串与基本数据类型之间的运算只能是链接运算:+。(得到的结果仍为一个字符串)
3.取模时,结果的符号取决于被模数。
4.扩展赋值运算符:+= -= *= /= %=,既可以实现运算,又不会改变变量的数据类型。

day03

1.switch-case语句中:

 switch(变量){
     case 常数值1:
     case 常数值2:
     ...
     default:
 }

“变量”可选的数据类型只能是以下六种:①char ②byte ③short ④int ⑤枚举类型 ⑥String(jdk1.7以后)
“常数值”只能是值,不能是范围。

day04

1.通过基本数据类型创建的数组:

  1. 对于byte short int long 而言,默认值为0;
  2. 对于float double 而言,默认值为0.0;
  3. 对于char而言,默认值为空格;
  4. 对于boolean而言,默认值为false。
    2.对于引用类型的变量构成的数组而言,默认初始化值为null。

day05

1.成员变量与局部变量:

1.1 成员变量:
①存在于内存空间中的堆空间中;
②如果在声明的时候不显式的赋值,那么不同数据类型仍有相应的默认初始化值。(见day03中的1. )。
1.2 局部变量:
①存在于内存空间中的栈空间中;
②一定要显式的赋值(局部变量没有默认初始化值)。

2.方法的重载(Overload)

2.1 满足条件:
①.同一个类中;
②.方法名必须相同;
③.方法的参数列表不同(情形一:参数个数不同;情形二:参数类型不同)
注:方法的重载与方法的返回值类型没有关系。

day06

1. 内存划分的结构:

1)栈(stack):局部变量、对象的引用名、数组的引用名;
2)堆(heap):new出来的“东西”(例:对象的实体,数组的实体)、含成员变量;
3)方法区:含字符串常量;
4)静态域:声明为static的变量。

2. 有可变个数的形参方法:

1)格式:对于方法的形参,格式为:(数据类型 … 形参名);
2)可变个数的形参方法与同名的方法之间构成重载;
3)可变个数的形参在调用时,个数从0开始,到无穷多个都可以;
4)使用可变多个形参的方法方法的形参使用数组来表示是一致的;
5)若方法中存在可变个数的形参,那么一定要声明在方法形参的的最后
6)在一个方法中,最多声明一个可变个数的形参。

3. 方法的参数传递
  1. ①形参:方法声明时,方法小括号内的参数;
    ②实参:调用方法时,实际传入的参数值。
  2. 规则:java中的参数传递机制:值传递机制
    1)形参是基本数据类型的,将实参的值传递给形参的基本数据类型的变量;
    2)形参是引用数据类型的,将实参的引用类型变量的值(对应的堆空间的对象实体的首地址值)传递给形参的引用类型变量。
4. 类的要素之一——构造器(构造方法 constructor)

1)构造器作用:①创建对象;②给创建的对象的属性赋值。
2)设计时,若不显式声明类的构造器,则程序会默认提供一个空参的构造器;
3)一旦显式地定义类的构造器,那么默认的构造器就不再提供;
4)声明类的构造器的格式:权限修饰符 类名(形参){ }
5)类的多个构造器之间构成重载。

5. 类对象的属性赋值的先后顺序

①属性的默认初始化;②属性的显示初始化;③通过构造器给属性初始化;④通过“对象.方法”的方式给属性赋值。

day07

1. this

1)可以用来修饰属性、方法、构造器;
2)this理解为当前对象或当前正在创建的对象;
3)可在构造器中通过“this(形参)”的方式显式地调用本类中其他重载的指定的构造器。

注:①其在构造器内部必须声明在首行;
②若一个类中有n个构造器,那么最多有n-1个构造器中使用了this(形参列表)。

2. package

1)用于声明源文件所在的包,写在程序的第一行。
2)每“.”一次,表示一层文件目录;
3)包名都要小写。

3. import

1)显式导入指定包下的类或接口;
2)写在包的声明和源文件之间;
3)如果需要引入多个类或接口,那么就并列写出;若多个方法位于同一个包中,可用“.*”;
4)如果导入的类是java.lang包下的,则就不需显式地声明。
5)若要导入两个同名的类,则其中一个类可通过如下方式:

例:在util包和sql包下同时存在Date类  
 java.sql.Date data = new java.sql.Data(参数)

6)import static 表示导入指定类的static的属性或方法
7)导入java.lang.*只能导入lang包下的所有类或接口,不能导入lang的子包下的类或接口。
例:

import static java.lang.System.*;
//则System.out.println()可写为:
out.println();
4.方法的重写(Override Overwrite)

1)前提:有子类继承父类;
2)子类继承父类以后,若父类的方法对子类不适用,则子类可以对父类的方法进行重写;
3)重写的规则:

/*
权限修饰符 方法的返回值 方法名(参数列表) 异常类型
*/
public void method1(int age, String[] str)throw Exception{

}

①要求子类方法的“返回值类型 方法名 (参数列表)”与父类的方法一样;
②子类方法的修饰符不能小于父类方法的修饰符;
③若父类方法抛异常,那么子类方法抛的异常类型不能大于父类的;
④子父类的方法必须同为static或同为非static。

day08

1. super关键字(可用于修饰属性、方法、构造器)

1)当子类与父类中有同名的属性时,可以通过“super.此属性”显式的调用父类中声明的属性;若想调用子类的同名的属性可通过“this.此属性”调用。
2)当子类重写父类的方法以后,在子类中若想再显式的调用父类的被重写的方法,就需要使用“super.方法”。
3)super修饰构造器,通过在子类中使用“super.(形参列表)”来显式的调用父类中指定的构造器。
①在构造器内部,“super(形参列表)”必须声明在首行;
②在构造器内部,“this(形参列表)”或“super(形参列表)”只能出现一个;
③当构造器中,不显式的调用“this(形参列表)”或“super(形参列表)”其中任何一个,默认调用的是父类空参的构造器。

注:在设计一个类时,尽量显式的提供一个空参的构造器。

2. 面向对象的第三个特征:多态性

1)多态性,可理解为一个事物的多种表象形态。①方法的重载与重写;②子类对象的多态性。
2)子类对象的多态性使用的前提:①要有类的继承;②要有子类对父类方法的重写。
3)程序运行分为编译状态和运行状态。对于多态性来说,编译时,“看左边”,将此引用变量理解为父类的类型;运行时,“看右边”,关注于真正对象的实体——子类的对象,那么执行的方法就是子类重写的。
4)子类对象的多态性,并不适用于属性!!

//例:
public class Person{
	...
	public Person(){
		super();
	}
	...
	public void walk(){
		System.out.println("人走路");
	}
}

public class Man extends Person{
	...
	public void walk(){
		System.out.println("男人走路");
}

public class Test{
	public static void main(String[] args){
		//子类对象的多态性,父类的引用指向子类对象
		Person p1 = new Man();
		//虚拟方法调用,通过父类的引用指向子类的对象实体,
		//当调用方法时,实际执行的是子类重写父类的方法。
		p1.walk();  //运行结果:男人走路
3. instanceof关键字

1)格式: 对象a instanceof 类A (含义:判断对象a是否是类A的一个实例,是,则返回true;否则,返回false)
注意:若对象a是A类的实例,则a的父类也一定是A类的父类的实例。

4. “==”与equals()

4.1 对于“==”:
1)若两端为基本数据类型,根据基本数据类型的值判断是否相等,相等返回true,否则返回false。注:两端数据类型可以不同,在不同的情况下,也可以返回true。
2)引用数据类型,比较引用类型变量的地址值是否相等。
4.2对于equals():
1)①只能处理引用类型变量;②在Object类中,equals()是比较两个引用变量的地址值是否相等。
注:java.lang.Object类是所有类的根父类。
2)String、包装类File类和Date类这些类重写了Object类的equals()方法,重写后比较的是==两个对象的“实体内容”==是否完全相同。
3)若希望自定义的一个类,实现比较两个对象的属性值都相同的情况下返回true,则需要重写Object类的equals(Object obj)方法。

day09

1. toString()方法
//java.lang.Object类的toString()方法的定义如下:
public String toString(){
	return getClass().getName() +"@" +Integer.toHexString(hashCode());
}

1)当用System.out.println()打印一个对象的引用时,实际上默认调用的是这个对象的toString()方法;
2)当打印的对象所在的类没有重写Object类中的toString()方法时,那么调用的就是Object中定义的toString()方法——即返回所在对象所在的类及对应的堆空间对象实体的首地址;
3)当打印的对象所在的类重写了toString()方法时,调用的就是该类重写的toString()方法;(常常重写为:将对象的属性信息返回)
4)像String类、包装类、File类、Date类等,已经实现了Object类中的toString()方法的重写。

2. 基本数据类型、包装类与String类型的相互转化

1)基本数据类型<----->包装类:JDK5.0以后,可实现自动装箱拆箱;
2)基本数据类型、包装类<----->String类:
①基本数据类型、包装类----->String类:调用String类重载的valueOf(Xxx x)方法;
②String类----->基本数据类型、包装类:调用包装类的parseXxx(String str)方法。

3. static关键字(可用于修饰属性、方法、代码块(或初始化块)、内部类)

1)static修饰属性(类变量):
①由类创建的所有的对象,都共用这一个属性;
②当其中一个对象对此属性进行修改,会导致其他对象对此属性的一个调用;
③类变量随着类的加载而加载的,并且独一份;
④静态的变量可以直接通过“类.类变量”的形式来调用
⑤类变量的加载是要早于对象的,所以当有对象以后,可以通过“对象.类变量”来使用类变量。注:“类.实例变量”是不行的。
⑥类变量存在于静态域中。

2)static修饰方法(类方法):
①随着类的加载而加载,在内存中也是独份;
②可以通过“类.类方法”的方式调用;
③内部可以调用静态的属性或静态的方法,而不能调用非静态的属性或方法。
注:静态的方法内是不可以有this或super关键字的!

day10

1.设计模式:设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。(共23种设计模式)
1.1单例的设计模式:

1)解决的问题:使得一个类只能够创建一个对象;
2)实现方式如下:

//法一:饿汉式
//只能创建Singleton的单个实例
class Singleton{
	//1.私有化构造器,使得在类的外部不能够调用此构造器
	private Singleton(){
	}
	//2.在类的内部创建一个类的实例
	//3.私有化此对象,通过公共的方法来调用
	private static Singleton instance = new Singleton();
	//4.此公共的方法,只能够通过类来调用,因为设置为static的,同时类的实例也必须为static声明的
	public static Singleton getInstance(){
		return instance;
	}
} 

//法二:懒汉法(存在线程安全问题!)
class Singleton{
	//1.私有化构造器,使得在类的外部不能够调用此构造器
	private Singleton(){
	}
	//2.私有化此对象,通过公共的方法来调用
	private static Singleton instance = null;
	//4.此公共的方法,只能够通过类来调用,因为设置为static的,同时类的实例也必须为static声明的,	在类方法的内部,若实例不存在则创建一个类的实例,否则返回已存在实例
	public static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
} 
2.类的第四个成员——初始化块(或代码块)

1)代码块有修饰的话,那么只能使用static;
2)分类:
一、静态代码块:
①里面可以有输出语句;
②随着类的加载而加载,而且只能被加载一次;
③多个静态代码块之间按照顺序结构执行;
④静态代码块的执行要早于非静态代码块的执行;
⑤静态的代码块中只能执行静态的结构(即类属性、类方法)
二、非静态代码块:
①可以对类的属性(静态的、非静态的属性都可)进行初始化操作,同时也可以调用本类声明的方法(静态的、非静态的方法都可);
②里面可以有输出语句;
③一个类中可以有多个非静态的代码块,多个代码块之间按照顺序结构执行;
④每创建一个类的对象,非静态代码块就加载一次;
⑤非静态代码块的执行要早于构造器。

关于属性的赋值操作顺序:①默认的初始化;②显式的初始化或代码块初始化(此处两个结构按照顺序执行);③构造其中;④通过方法对对象的相应属性进行修改。

3. fianl关键字:可用来修饰类、属性、方法

1)final修饰类:这个类就不能被继承。如:String类、StringBuffer类、System类。
2)final修饰方法:不能被重写。如:Object类的getClass()方法。
3)final修饰属性:
①此属性就是一个常量,一旦初始化后,不可再被赋值。习惯上,常量用大写字母表示。
②此常量的赋值位置:一、可显式的赋值、代码块、构造器;二、不可使用默认初始化。

注:当变量用static final修饰时,称为全局常量。

4. abstract关键字:可用来修饰类、方法

4.1当abstract修饰类时,称为抽象类
1)不可被实例化;
2)抽象类有构造器(凡是类都有构造器);
3)抽象方法所在的类一定是抽象类;
4)抽象类中可以没有抽象方法。

4.2当abstract修饰方法时,称为抽象方法
1)格式:没有方法体,如:public abstract void method();
2)抽象方法只保留方法的功能,而具体的实现与执行,交给继承抽象类的子类,由子类重写此抽象方法;
3)若子类继承抽象类,并重写了所有的抽象方法,则此类是一个非抽象类,即可以实例化。
4)若子类继承抽象类,没有重写所有的抽象方法,意味着此类中仍然有抽象方法,则此类必须声明为抽象的。
5)abstract不能用来修饰属性、构造器、private、final、static。

4.接口(interface)是与类并行的一个概念

1)接口可以看做是一个特殊的抽象类,是一个常量与抽象方法的集合,即不能包含变量和一般的方法。
注:接口中所有的常量都默认用public static final修饰;所有的抽象方法都用public abstract修饰。
2)接口是没有构造器的。
3)接口定义的就是一种功能,此功能可以被类所实现(implements)。
4)实现接口的类,必须要重写其中的所有的抽象方法,才可实例化。若没有重写所有的抽象方法,则此类仍需定义为一个抽象类。
5)类可以实现多个接口,但java中类的继承是单继承。
6)接口与接口之间也是继承关系,且可以实现多继承。
7)接口与具体的实现类之间也存在多态

day11

1.异常处理

一、

java.lang.Throwable
          |--------Error:错误,程序中不进行处理
          |--------Exception:异常,要求在编写程序中,就要考虑对这些异常的处理
                     |--------编译时异常:在编译期间会出现的异常(执行javac.exe命令时,出现异常)
                     |--------运行时异常(RuntimeException):在运行期间出现的异常(执行java.exe命令时,出现异常)

当执行一个程序是,如果出现差异,那么异常之后的代码就不再执行。

二、如何处理Exception异常(java提供的是异常处理的抓抛模型)
1)“抛”:当执行代码时,一旦出现异常,就会在异常的代码处生成一个对应的异常类型的对象,并将此对象抛出。
“抛“分为两类:
第一类:自动抛出
第二类:手动抛出(throw + 异常类的对象,例如:throw new RuntimeException(“传入的类型有误!”); )注:其中的“异常类的对象”对应的异常类,既可以是现成的异常类,也可以是自己创建的异常类。

①一旦抛出此异常对象,那么程序就终止执行;
②此异常类的对象抛给方法的调用者。
③抛出的异常类型,若是RuntimeException(运行时异常),可以不显式的处理;若是一个Exception(包含编译时异常和运行时异常),则必须要显式的处理。
④子类重写父类的方法,其抛出的异常类型只能是被重写的方法的异常类型的子类或异常类型一样。

2)“抓”:抓住上一步抛出的异常类的对象。如何“抓”,即为异常处理的方式。
java提供了两种方式用来处理一个异常的对象。

异常处理方式一:

try{
   //可能出现异常的代码
}catch(Exception1 e){
   //处理方式1
}catch(Exception2 e){
   //处理方式2
}finally{
   //一定要执行的代码
}

①try内声明的变量,类似于局部变量,出了try{ }语句的范围,就不能被调用;
②finally是可选的;
③catch语句内部是对异常对象的处理;>getMessage();
>printStackTrace();
④可以有多个catch语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足就执行catch中的代码。执行完,就跳出其后的多条catch语句。
⑤若果异常处理了,那么其后的代码继续执行。
⑥若catch中多个异常类型是“并列”关系,孰上孰下都可以;若catch中多个异常类型是“包含”关系,须将子类放在父类的上面,否则报错!
⑦finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句。
⑧try-catch是可以嵌套的。

异常处理方式二:
在方法的声明处,显式的抛出异常对象的类型。
格式:例如:

public void method() throws FileNotFoundException, IOException{
    ...
}

①当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。
②异常的对象可以逐层向上抛,直至main中。当然在向上抛的过程中,可以再通过try-catch-finally进行处理。

三、

①对于运行时异常来说,可以不显式地进行处理。
②对于编译时异常来说,必须要显示的进行处理。

day12

1.集合

1)存储对象可以考虑:①数组;②集合。
2)数组存储对象的弊端:①一旦创建,其长度不可变;②真实的数组存放的对象的个数是不可知的。
3)集合:

Collection接口
	|------List接口:存储有序的、可重复的元素。(相当于动态数组)
	          |------ArrayList(主要的实现类)
	          |------LinkedList(更适用于频繁的插入、删除操作)
	          |------Vector(古老的实现类、线程安全的,但效率要低于ArrayList)
	|------Set接口:存储无序的、不可重复的元素。
	          |------HashSet(主要的实现类)
	          |------LinkedHashSet(是HashSet的子类,当需要频繁的遍历集合元素且增删改动较少时使用)
	          |------TreeSet(可以按照添加进集合中的元素的指定属性进行排序)
Map接口:存储“键——值”对的数据
    |------HashMap(主要的实现类,可以添加null健、null值)
    |------LinkedHashMap(是HashMap的子类,可以按照添加进Map的顺序实现遍历)
    |------TreeMap(需要按照key所在类的指定属性进行排序。要求key是同一个类的对象。对key考虑使用自然排序和定制排序)
    |------Hashtable(古老的实现类,线程安全的,但不建议使用。不可添加null键、null值不建议使用)
             |------子类:Properties(常用来处理属性文件。键和值都为String类型的)
2. Collection接口

方法:
1.add(Object obj);
2.addAll(Collection coll);
3.size();
4.clear();
5.isEmpty();
6.remove(Object obj);
7.removeAll(Collection coll);
8.retainAll(Collection coll);
9.equals(Object obj);
10.contains(Object obj);
11.containsAll(Collection coll);
12.hashCode();
13.iterator();
14.toArray();

3. 集合中的List接口

1)除了继承了Collection接口中的方法外,新增的方法:
1.删除remove(int index);
2.修改set(int index,Object obj);
3.获取get(int index);
4.插入add(int index,Object obj)

2)添加进List集合中的元素(或对象)所在的类一定要重写equals()方法

day13

1. 集合中的Set接口:存储无序的、不可重复的元素。

1)无序性:无序性≠随机性。真正的无序性,指的是元素在底层存储的位置是无序的。
2)不可重复性:当向Set中添加进相同的元素的时候,后面的这个不能添加进去。
注:要求添加进Set中的元素所在的类,一定要重写equals()和hasCode()方法。进而保证Set中元素的不可重复性!
3)Set中的元素是如何存储的?使用了哈希算法。
当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算此对象的哈希值,此哈希值决定了此对象在Set中的存储位置。若此位置之前没有对象存储,则这个对象直接存储到此位置。若此位置已有对象存储,再通过equals()比较这两个对象是否相同。若果相同,后一个对象就不能再添加进来。万一返回false,
注:要求hashCode()方法和equals()方法保持一致
4)Set使用的方法基本都是Collection接口定一下的。

2. LinkedHashSet

1)使用链表维护了一个添加进集合中的顺序。导致当我们遍历LinkedHashSet集合元素时,是按照添加进去的顺序遍历的。
2)LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能。

3. TreeSet

1)向TreeSet中添加的元素必须是同一个类的
2)可以按照添加进集合中的元素的指定顺序遍历。例如:对于String,包装类等默认按照从小到大的顺序遍历。
3)当向TreeSet中添加自定义类的对象时,有两种方法:①自然排序;②定制排序。
一、自然排序
①步骤:
第一步:要求自定义类实现java.lang.Comparable接口(即:要求添加进TreeSet中的元素所在的类implements Comparable接口)
第二步:重写其compareTo(Object obj)的抽象方法,在此方法中,指明按照自定义类的哪个属性进行排序。
第三步:向TreeSet中添加元素即可。若不实现此接口,会报运行时异常。
②向TreeSet中添加元素时,首先按照compareTo()进行比较,一旦返回0,虽然仅是两个对象的此属性值相同,但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来。
注:compareTo()与hashCode()以及equals()三者必须保持一致!
二、定制排序
①步骤:
第一步:创建一个实现了Comparator接口的实现类的对象。在实现类中重写Comparator的compare(Object o1, Object o2)方法;
第二步:在此compare()方法中指明按照元素所在类的哪个属性进行排序;
第三步:将此实现Comparator接口的实现类的对象作为形参传递给TreeSet的构造器中;
第四步:向TreeSet中添加元素即可。若不实现此接口,会报运行时异常。
注:compare()与hashCode()以及equals()三者必须保持一致!

4. Map接口

1)方法:
1.Object put(Object key, Object value):向Map中添加一个元素
2.Object remove(Object key):按照指定的key删除此key-value
3.void putAll(Map t)
4.void clear():清空
5.Object get(Object key):获取指定key的value值。若无此key,则返回null
6.boolean containsKey(Object key)
7.boolean containsValue(Object value)
8.int size():返回集合长度
9.boolean isEmpty()
10.equals(Object obj)
2)遍历Map:
1.Set keySet():获取key集

例:遍历key集
Set set = map.keySet();
for(Object obj : set){
	System.out.println(obj);
}

2.Collection values():获取value集

例:遍历value集
Collection values = map.values();
Iterator i = values.iterator();
while(i.hasNext()){
	System.out.println(i.next());
}

3.Set entrySet():获取entry集

例:遍历key-value对
方式一:
Set set1 = map.keySet();
for(Object obj : set1){
	System.out.println(obj + "--->" + map.get(obj));
}
方式二:
Set set2 = map.entrySet();
for(Object obj : set2){
	Map.Entry entry = (Map.Entry)obj;
	System.out.println(entry);
	//或者:System.out.println(entry.getKey() + "--->" + entry.getValue());
5. HashMap类

1)HashMap中,key是用Set来存放的,不可重复。value是用Collection来存放的,因此可重复的。
2)一个key-value对,是一个Entry。所有的Entry使用Set存放的,因此也是不可重复的。
3)向HashMap中添加元素时,会调用key所在类的equals()方法来判断两个key是否相同。若相同则只能添加进后添加的那个元素。
4)HashMap判断两个key相等的标准:两个key通过equals()方法返回true,hashCode值也相等。
5)HashMap判断两个value相等的标准:两个value通过equals()方法返回true。

6.LinkedHashMap类

使用链表维护添加进Map中的顺序,故遍历Map时,是按添加的顺序遍历的。

7.TreeSet类

1)按照添加进Map中的元素的key的指定属性进行排序。要求key必须是同一个类的对象。
2)针对key来说,如同TreeSet,有自然排序和定制排序两种;实现方式类似TreeSet中的实现方式。

8.Hashtable

1)是一个古老的Map实现类,是线程安全的。
2)与HashMap不同的是,Hashtable不允许使用null作为key和value。
3)Hashtable判断两个key相等、两个value相等的标准与HashMap一致。

9.Hashtable的子类:Properties类

常用来处理属性文件。键和值都为String类型的。

例:使用Properties处理属性文件
public void test() throws FileNotFoundException, IOException{
	Properties pros = new Properties();
	pros.load(new FileInputStream(new File("jdbc.properties")));
	String user = pros.getProperty("user")  //获取键user对应的值
	System.out.println(user);
}
10. Iterator接口

用于遍历集合Collection元素

11. Collections工具类(操作Collection及Map的工具类,方法大部分是static的)

1)排序:
①reverse(List):反转List中的元素顺序
②shuffle(List):对List集合元素进行随机排序
③sort(List):根据元素的自然顺序对制定List集合元素按升序排序
④sort(List, Comparator):根据制定的Comparator产生的顺序对List集合元素进行排序
⑤swap(List, int ,int):将制定list集合中的i处元素和j处元素进行交换

2)查找、替换
①Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素。
②Object max(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素。
③Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素。
④Object min(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素。
⑤int frequency(Collection, Object):返回指定集合中指定元素的出现次数。
⑥void copy(List dest, List src):将src中的内容复制到dest中。

实现List的复制
错误的实现方式:
List list = new ArrayList();
List newlist = new ArrayList();
Collections.copy(newlist, list);
正确的实现方式:
List list = new ArrayList();
List newlist = Arrays.asList(new Object[list.size()]);
Collections.copy(newlist, list);

⑦boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值.

3)同步控制
Collections类中提供了多个synchronizedXxx()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。

4)Enumeration
Enumeration接口是iterator迭代器的“古老版本”。

例:
Enumeration stringEnum = new StringTokenizer("a-bc*-de-fgh", "-");
while(stringEnum.hasMoreElements()){
	System.out.println(stringEnum.nextElement());
}

day14

1.泛型

1)自定义泛型类的使用
①当实例化泛型类的对象是,指明泛型的类型。指明后,对应的类中所有使用泛型的位置,都变为实例化中指定的泛型的类型。
②如果我们自定义了泛型类,但是在实例化时没有使用,那么默认类型是Object类的。

2)泛型与继承的关系
A类是B类的子类,G是带泛型声明的类或接口。那么G<A>不是G<\B>的子类。
例:使类A是类B的子类,但List<A>依然不是List<B>的子接口,它们是并列关系。

3)通配符:?
A类是B类的子类,G是带泛型声明的类或接口。那么G<?>是G<A>和G<B>的父类。
①例如:List<A>、List<B>等,都是List<?>的子类。其中,List<?>能读取其中的数据,因为不管存储的是什么类型的元素,其一定是Object类的或其子类的;但是不可以向List<?>中写入数据,因为没有指明可以存放到其中的元素的类型,唯一例外的是null。
②? extends A :表示可以存放A及其子类。
例:List<? extends A >
③? super A :表示可以存放A及其父类。
例:List<? super A >

4)注意事项:
静态方法中不能使用类的泛型;
②如果泛型类是一个接口或抽象类,则不可以创建泛型类的对象;
③不能载catch中使用泛型;
④从泛型类派生子类,泛型类型需具体化。

可以读取声明为通配符的集合类的对象
List<String> list1 = new ArrayList<String>();
list1.add("aa");
List<?> list2 = list1;

Iterator<?> iterator = list2.iterator();
while(iterator.hasNext()){
	System.out.println(iterator.next());
}

但不允许向声明为通配符的集合类中写入对象,唯一例外的是null
例:list2.add(123);
	list2.add("bb");
都是错误的!!但是可以存null!
2.枚举类

1)如何自定义枚举类

自定义枚举类示例:
class Season{
	1.提供类的属性,声明为private final
	private final String seasonName;
	2.声明为final的属性,在构造器中初始化。
	private Season(String seasonName){
		this.seasonName = seasonName;
	}
	3.通过公共的方法来调用属性。
	public String getSeasonName(){
		return seasonName;
	}
	4.创建枚举类的对象
	public static final Season SPRING = new Season("spring");
	public static final Season SUMMER = new Season("summer");
	public static final Season AUTUMN = new Season("autumn");
	public static final Season WINTER = new Season("winter");
}

2)如何使用enum关键字定义枚举类

使用enum关键字定义枚举类示例:
enum Season{
	SPRING("spring"),
	SUMMER("summer"),
	AUTUMN("autumn"),
	WINTER("winter");
	
	private final String seasonName;

	private Season(String seasonName){
		this.seasonName = seasonName;
	}

	public String getSeasonName(){
		return seasonName;
	}
}

①常用方法

1.values()

Season[] seasons = Season.values();//获取Season类的所有枚举对象
for(int i = 0; i < seasons.length; i++){
	System.out.println(seasons[i]);
}
输出结果:
Season [seasonName=spring]
Season [seasonName=summer]
Season [seasonName=autumn]
Season [seasonName=winter]

2.valueOf(String name):要求传入的形参name是枚举类对象的名字。
  否则报java.lang.IllegalArgumentException异常。
  
String str = "SPRING";
Season aSeason = Season.valueOf(str);
System.out.println(aSeason);
输出结果:
Season [seasonName=spring]

②让枚举类实现接口
可以让不同的枚举类的对象调用被重写的抽象方法,执行的效果不同。(相当于让每个对象重写抽象方法)

interface Info{
	void show();
}

enum Season implements Info{
	SPRING("spring"){
		public void show(){
			System.out.println("春暖花开");
		}
	},
	SUMMER("summer"){
		public void show(){
			System.out.println("夏日炎炎");
		}
	},
	AUTUMN("autumn"){
		public void show(){
			System.out.println("秋高气爽");
		}
	},
	WINTER("winter"){
		public void show(){
			System.out.println("白雪皑皑");
		}
	};
	
	private final String seasonName;

	private Season(String seasonName){
		this.seasonName = seasonName;
	}

	public String getSeasonName(){
		return seasonName;
	}
}

此时执行代码:

String str = "AUTUMN";
Season aSeason = Season.valueOf(str);
aSeason.show();
输出结果:
秋高气爽
3. 注解Annotation

1)JDK提供的常用的注解
① @Override :限定重写父类方法,该注释只能用于方法
② @Deprecated : 用于表示某个程序元素(类、方法等)已过时
③ @SuppressWarnings :抑制编译器警告

2)如何自定义一个注解

3)元注解

day15 IO

1. java.io.File类

1)凡是与输入、输出相关的类、接口等都定义在java.io包下;
2)File是一个类,可以有构造器创建其对象。此对象对应着一个文件(可以是.txt、.avi、.doc等)或者文件目录;
3)File类对象是与平台无关的;
4)File中的方法,仅涉及到如何创建、删除、重命名等,但涉及文件内容时,File是无能为力的,只能由io流来完成;
5)File类的对象常作为io流的具体类的构造器的形参。
6)对于路径:
①相对路径:在当前文件目录下的文件的路径
②绝对路径:包括盘符在内的完整的文件路径
7)File类中的方法

1.访问文件名
getName()
getPath()
getAbsoluteFile()
getAbsolutePath()
getParent()
renameTo(File newName):重命名。例:对于file1.renameTo(file2):file1重命名为file2。要求:file1文件一定存在,file2一定不存在。
2.获取常规文件信息
lastModified()
length()
3.文件检测
exists()
canWrite()
canRead()
isFile()
isDirectory()
4.文件操作相关
createNewFile()
delete()
5.目录操作相关
mkDir():创建一个文件目录。只有在上层文件目录存在的情况下,才能返回true。
mkDirs():创建一个文件目录。若上层文件目录不存在,则一并创建。
list()
listFiles().

2. 流的分类与Io的体系

1)流的分类
①按照数据流向的不同:输入流、输出流
②按照处理数据的单位不同:字节流 、字符流(用于处理文本文件)
③按照角色的不同:节点流(直接作用于文件的流)、处理流
2)IO的体系

抽象基类节点流(文件流)缓冲流(处理流的一种,可以提升文件操作的效率
字节输入流InputStreamFileInputStreamBufferedInputStream
常用方法:int read(byte[] b)常用方法:int read(byte[] b)
字节输出流OutputStreamFileOutputStreamBufferedOutputStream
常用方法:void write(b,0,len)常用方法:void write(b,0,len))(write()后记得调用flush())
字符输入流ReaderFileReaderBufferedReader
常用方法:int read(char[] c)常用方法:int read(char[] c)或String readLine()(readLine()用于读一行)
字符输出流WriterFileWriterBufferedWriter(write()后记得调用flush())
常用方法:void write(c,0,len)常用方法:void write(c,0,len)或void write(String str)

注:①从硬盘中读入一个文件,要求此文件一定得存在。若不存在,报FileNotFoundException;
②从程序中输出一个文件到硬盘,此文文件可以不存在。若不存在,就创建一个实现输出。若存在,则将一存在的文件覆盖;
③真正开发时,就使用缓冲流来代替节点流;
④注意最后要关闭相应的流。先关闭输出流,再关闭输入流。(此操作放在finally中)

3. FileInputStream的使用
1.创建一个FileInputStream类的对象。
FileInputStream fis = new FileInputStream (file);
try{
	2.创建一个File类的对象,并实例化fis。
	File file = new File("HelloWorld.txt");
	fis = new FileInputStream (file);
	3.调用FileInputStream的方法,实现file文件的读取。
	byte[] b = new byte[5];  //读取到的数据要写入的数组
	int len;  //每次读入到byte中的字节的长度
	while((len = fis.read(b)) != -1){
		String str = new String(b, 0 ,len);
		System.out.println(str);
	}
}catch(IOException e){
	e.printStackTrace();
}finally{
	4.关闭相应的流
	if(fis != null){
		try{
			fis.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}
4. FileOutputStream的使用
1.创建一个File对象,表明要写入的文件位置。
  输出的物理文件可以不存在,当执行过程中,若不存在,会自动的创建。若存在,会将原有的文件覆盖。
File file = new File("HelloWorld.txt");
2.创建一个FileOutputStream的对象,将file的对象作为形参传递给FileOutputStream的构造器。
FileOutputStream fos = null;
try{
	fos = new FileOutputStream();
	3.写入的操作
	fos.write(new String("Hello World!").getBytes());
}catch(Exception e){
	e.printStackTrace());
}finally{
	4.关闭输出流
	if(fos != null){
		try{
			fos.close();
		}catch(IOException e){
			e.printStackTrace());
		}
	}
}
5. FileInputStream与FileOutputStream的联合使用
实现文件的复制
public static void copyFile(String src, String dest){
	1.提供读入、写出的文件
	File file1 = new File(src);
	File file2 = new File(dest);
	2.提供相应的流
	FileInputStream fis = null;
	FileOutputStream fis = null;
	try{
		fis = new FileInputStream(file1);
		fos = new FileOutputStream (file2);
		3.实现文件的复制
		byte[] b = new byte[20];
		int len;
		while((len = fis.read(b) != -1){
			fos.write(b, o, len);
		}
	}catch(Exception e){
		e.printStackTrace();
	}finally{4.关闭输出流、输入流
		if(fos != null){
			try{
				fos.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		if(fis != null){
			try{
				fis.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
	}
}
5. FileReader与FileWriter的联合使用

使用FileReader和FileWriter可以实现文本文件的复制。
对于非文本文件,只能使用字节流!

实现文件的复制
public static void copyFileByChar(String src, String dest){
	1.提供读入、写出的文件
	File file1 = new File(src);
	File file2 = new File(dest);
	2.提供相应的流
	FileReader fr = null;
	FileWriter fw = null;
	try{
		fr = new FileReader(file1);
		fw = new FileWriter(file2);
		3.实现文件的复制
		char[] b = new char[24];
		int len;
		while((len = fr.read(b) != -1){
			fw.write(b, o, len);
		}
	}catch(Exception e){
		e.printStackTrace();
	}finally{4.关闭输出流、输入流
		if(fw != null){
			try{
				fw.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		if(fr != null){
			try{
				fr.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
	}
}
6. BufferedInputStream与BufferedOutputStream的联合使用
实现文件的复制,可以提升文件传输的效率
public static void copyFile(String src, String dest){
	BufferedInputStream bis = null;
	BufferedOutputStream bos = null;
	try{
		1.提供读入、写出的文件
		File file1 = new File(src);
		File file2 = new File(dest);
		2.创建需要的节点流
		FileInputStream fis = new FileInputStream(file1);
		FileOutputStream fis = new FileOutputStream (file2);
		3.将创建的节点流的对象作为形参传递给缓冲流的构造器
		bis = new BufferedInputStream(fis);
		fos = new BufferedOutputStream(fos);
		4.实现文件的复制
		byte[] b = new byte[1024];
		int len;
		while((len = bis.read(b) != -1){
			bos.write(b, o, len);
			bos.flush();
		}
	}catch(Exception e){
		e.printStackTrace();
	}finally{4.关闭输出流、输入流
		if(bos!= null){
			try{
				bos.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		if(bis != null){
			try{
				bis.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
	}
}
6. BufferedReader与BufferedWriter的联合使用

类似5中BufferedInputStream与BufferedOutputStream的使用。

7. 转换流——InputStreamReader与OutputStreamWriter:实现字节流与字符流间的转换

1)InputStreamReader:输入时,实现字节流到字符流的转换,提高操作的效率(前提是数据是文本文件)解码:字节数组----->字符串;
2)OutputStreamWriter:输出时,实现字符流到字节流的转换。编码:字符串---->字节数组。

3)应用例子:

实现文件的复制,可以提升文件传输的效率
public static void copyFile(String src, String dest){
	BufferedReader br= null;
	BufferedWriter bw= null;
	try{
		解码:
		File file1 = new File(src);
		FileInputStream fis = new FileInputStream(file1);
		InputStreamReader isr = new InputStreamReader(fis, "GBK");
		br = new BufferedReader(isr);
		编码:
		File file2 = new File(dest);
		FileOutputStream fis = new FileOutputStream(file2);
		OutputStreamWriter osw = new OutputStreamWriter(fis);
		bw = new BufferedWriter(osw);
		
		String str;
		while((str= br.readLine() != null){
			bw.write(str);
			bw.newLine();
			bw.flush();
		}
	}catch(Exception e){
		e.printStackTrace();
	}finally{4.关闭输出流、输入流
		if(bw!= null){
			try{
				bw.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		if(br!= null){
			try{
				br.close();
			}catch(IOException e){
				e.printStackTrace();
			}
		}
	}
}
8.标准的输入输出流:System.in与System.out

例子:从键盘输入字符串,要求将读取到的整行字符串转换成大写输出。然后继续进行输入操作。直至当输入“e”或者“exit”时,退出程序。

public class TestStandardStream {

	public static void main(String[] args) {
		BufferedReader br = null;
		try {
			InputStream is = System.in;
			InputStreamReader isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			String str;
			while(true) {
				System.out.println("请输入字符串:");
				str = br.readLine();
				if(str.equalsIgnoreCase("e") || str.equalsIgnoreCase("exit")) {
					break;
				}
				String str1 = str.toUpperCase();
				System.out.println(str1);
			}
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			if(br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

}

day16

1. 打印流:PrintStream(字节打印流)与PrintWriter(字符打印流)

1)PrintStream和PrintWriter的输出不会抛出异常;
2)PrintStream和PrintWriter有自动flush()功能;
3)以PrintStream为例:

FileOutputStream fos = null;
try {
	fos = new FileOutputStream(new File("print.txt"));
}catch(IOException e) {
	e.printStackTrace();
}
//创建打印输出流,设置为自动刷新模式(即写入换行符或字节'\n'时,都会刷新输出缓冲区
PrintStream ps = new PrintStream(fos, true);
if(ps != null) {
	System.setOut(ps); //使输出位置设置为ps打印流的位置,而不再是控制台
}
for(int i = 0; i <= 255; i++) { //输出ASCII码
	System.out.print((char)i);
	if(i % 50 == 0) {
		System.out.println();
	}
}
ps.close();
2. 数据流DataInputStream和DataOutputStream——用于读取和写出基本数据类型的数据

1)数据流需套接在节点流FileInputStream、FileOutputStream上。
2)DataInputStream中的方法

boolean readBoolean()byte readByte()
char readChar()float readFloat()
double readDouble()short readShort()
long readLong()int readInt()
String readUTF()void readFully(byte[] b)

3)DataOutputStream中的方法

boolean writeBoolean()byte writeByte()
char writeChar()float writeFloat()
double writeDouble()short writeShort()
long writeLong()int writeInt()
String writeUTF()void writeFully(byte[] b)
2. 对象流——ObjectIntputStream与ObjectOutputStream

1)用于存储和读取对象的处理流。

2)序列化(Serialize):用ObjectOutputStream类将一个Java对象写入IO流中;

3)反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象;
注:ObjectIntputStream和ObjectOutputStream不能序列化statictransient修饰的成员变量。

4)对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象;序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。

5)如果需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:①Serializable(一般使用该接口);②Externalizable。
同时,要求类的属性(可以是该属性的父类实现该接口)同样的要实现Serializable接口

6)凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID;
②serialVersionUID用来表明类的不同版本间的兼容性;
③如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的源代码作了修改,serialVersionUID 可能发生变化。故建议显示声明。

7)显示定义serialVersionUID的用途:
①希望类的不同版本对序列化兼容,因此需确保类的不同版本具有相同的serialVersionUID;
②不希望类的不同版本对序列化兼容,因此需确保类的不同版本具有不同的serialVersionUID;

8)由1)~7)可知:实现序列化机制的对象对应的类的要求:
①要求类要实现Serializable接口;
②同时要求类的所有属性也必须实现Serializable接口;
③要求给类提供一个序列版本号:private static final long serialVersionUID;
④声明为static或transient的属性,不可以实现序列化。

3. RandomAccessFile

1)其既可以充当一个输入流,又可以充当一个输出流;
2)支持从文件的开头读取、写入(覆盖);
3)支持从任意位置的读取、写入(覆盖);利用seek(long pos)方法,从定位指针位置。
例如:将“ABC”插入文件HelloWorld.txt中内容“Hello World!”中的’e’后:

RandomAccessFile raf = null;
try {
	raf = new RandomAccessFile(new File("HelloWorld.txt"), "rw");
	raf.seek(2);
	byte[] b = new byte[24];
	int len;
	StringBuffer sb = new StringBuffer();
	while((len = raf.read(b)) != -1) {
		sb.append(new String(b, 0, len));
	}
	raf.seek(2);
	raf.write("abc".getBytes());
	raf.write(sb.toString().getBytes());
}catch (Exception e) {
	e.printStackTrace();
}finally {
	if(raf != null) {
		try {
			raf.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
4. 多线程

1)创建多线程的第一种方式:继承Thread类的方式创建多线程
①创建一个继承与java.lang.Thread类的子类;
②重写Thread类的run()方法,方法内实现此线程要完成的功能;
③创建一个该子类的对象;
④调用线程的start()方法,启动此线程,调用相应的run()方法。
注:一个线程只能够执行一次start();且不能通过Thread实现类对象的run()方法去启动一个线程。
例:

1.创建一个继承与java.lang.Thread类的子类;
class SubThread extends Thread{
	2.重写Thread类的run()方法,方法内实现此线程要完成的功能;
	public void run(){
		//实现此线程要完成的功能的代码
	}
}

public class TestThread{
	public static void main(String[] args){
		3.创建一个该子类的对象;
		SubThread st = new SubThread();
		4.调用线程的start()方法,启动此线程,调用相应的run()方法。
		st.start();
	}
}

2)创建多线程的第二种方式:通过实现Runnable接口的方式

1.创建一个实现Runnable接口的类
class ImpltRable impments Runnable{
	2.实现接口的抽象方法
	public void run(){
		//子线程执行的代码
	}
}

public class TestThread{
	public static void main(String[] args){
		3.创建一个Runnable接口实现类的对象
		ImpltRable ir = new ImpltRable();
		4.将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象,此对象即为一个线程;
		Thread t1 = new Thread(ie);
		5.调用start()方法,从而启动线程并自动执行run()方法。
		t1.start();
		//再创建一个线程
		Thread t2 = new Thread(ir);
		t2.start();
	}
}

3)“继承的方式”与“实现的方式”的对比:
相比较之下,“实现的方式”由于“继承的方式”。
优势如下:
①避免了java单继承的局限性;
②如果多个线程要操作同一份资源(或数据),更适合使用实现的方式。

5. Thread类常用的方法:

1)start():启动线程并执行相应的run()方法;
2)run()子线程要执行的代码放入run()方法中;
3)currentThread():静态的,调取当前的线程对象
4)getName():获取此线程的名字
5)setName():设置此线程的名字
6)yield():调用此方法的线程释放当前CPU的执行权;
7)join():在A线程中调用B线程的join()方法,表示当执行到此方法时,A线程停止执行,直至B线程执行完毕,A线程再接着join()之后的代码执行;
8)isAlive():判断当前线程是否还存活;
9)sleep(long l):显示的让当前线程睡眠l毫秒;
10)设置线程的优先级:
①getPriority():返回线程优先级;
②setPriority(int newPriority):改变线程的优先级(县城创建时继承父线程的优先级)
注:MAX_PRIORITY(10)、MIN_PRIORITY(1)、NORM_PRIORITY(5)(默认值)

day17

1. 线程的同步机制

线程的同步机制用于解决线程的安全问题。
1)方式一:同步代码块

synchronized(同步监视器){
	//需要被同步的代码块(即为操作共享数据的代码)
}

注意事项:
①共享数据:即多个线程共同操作的同一个数据(变量);

②同步监视器:其俗称为:锁。由任意一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。要求所有的线程必须共用同一把锁(即同一个对象)!

③在实现的方式中,通过实现Runnable接口的方式来创建多线程时,可以使用this来充当锁;但是通过继承Thread类的方式创建多线程时,慎用this(要明确各个线程this指代的对象是否是同一个)。


会导致释放锁的方法:wait()。
不会导致释放锁的方法:sleep()、yield()、suspend()(该方法已过时,因为该方法可能导致死锁)。

2)方式二:同步方法
将操作共享数据的方法声明为synchronized,即此方法为同步方法。能够保证当其中一个线程执行此方法时,其他线程在外等待直至此线程执行完此方法。
注意:使用同步方法时,也是隐式含有同步监视器(锁)的,且为this(即引用该方法的当前对象!)

例:
public synchronized void method(){
	//需要被同步的代码块(即为操作共享数据的代码)
}
2. 利用同步机制解决单例模式中懒汉式的线程安全问题:
class Singleton{
	private Singleton(){
	}
	
	private static Singleton getInstance(){
		if(instance == null){
			synchronized(Singleton.class){
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
	
}

①对于非静态方法而言,使用同步方法的话,默认锁为this。若果使用在继承的方式实现多线程的话,则要慎用!(要考虑好this在其中指代哪个对象)
②但对于静态方法而言,使用同步方法的话,使用当前类本身充当同步监视器(锁),即默认锁为:当前类本身。例如上面的Singleton.class。

3. 线程通信

1)线程通信常用的三个方法:
①wait():当在同步中,执行到此方法时,则此线程“等待”,直至其他线程执行notify()的方法,将其唤醒,唤醒后继续其wait()后的代码;
②notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待;
③notifyAll():唤醒正在排队等待资源的所有线程结束等待。

2)java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常。

day18 Java常用类

1. String类

1)String代表不可变的字符序列。底层使用char[]存放;String是final的。
2)方法:

方法介绍
public int length()
public char charAt(int index)返回在指定index位置的字符,index从0开始。
public boolean equals(Object anObject)比较两个字符串是否相等。相等返回true,否则返回false。
public int compareTo(String anotherString)
public int indexOf(String s)返回s字符串在当前字符串中首次出现的位置。若没有,返回-1。
public indexOf(String s, int startpoint)返回s字符串从当前字符串startpoint位置开始首次出现的位置。
public int lastIndexOf(String s)返回s字符串最后一次在当前字符串出现的位置,若无,则返回-1。
public int lastIndexOf(String s, int startpoint)
public boolean startsWith(String prefix)判断当前字符串是否以prefix开始。
public boolean endsWith(String suffix)判断当前字符串是否以suffix结束。
public boolean regionMatches(int firstStart, String other, int otherStart, int length判断当前字符串从firstStart开始的子串与另一个字符串other从otherStart开始,length长度的字符串是否equals。
public String subString(int startpoint)
public String subString(int start, int end)返回从start开始到end结束的一个左闭右开的子字符串。
public String replace(char oldChar,char newChar)
public String trim()丢除当前字符串中出现的空格,若有多个,就去除多个。
public String concat(String str)连接当前字符串与str
public String[] split(String regex)按照regex将当前字符串拆分,拆分为多个字符串,整体返回值为String[]。

3)字符串与基本数据类型、包装类之间的转换:
①字符串------>基本数据类型、包装类:调用包装类的parseXxx(String str);
②基本数据类型、包装类------>字符串:调用字符串的重载的valueOf()方法。

4)字符串与字节数组间的转换:
①字符串------>字节数组:调用字符串的getBytes();
②字节数组------->字符串:调用字符串的构造器。

5)字符串与字符数组间的转换:
①字符串------>字符数组:调用字符串的toCharArray();
②字符数组------>字符串:调用字符串的构造器。

6)String与StringBuffer之间的转换:
①String------>StringBuffer:使用StringBuffer的构造器new StringBuffer(String str)。
②StringBuffer------>String:使用StringBuffer的toString()方法。

2. StringBuffer类

1)java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删操作。
2)方法:

StringBuffer append(String s)StringBuffer append(int n)
StringBuffer append(Object o)StringBuffer append(char n)
StringBuffer append(long n)StringBuffer append(boolean n)
StringBuffer insert(int index, String str)从第index的位置插入字符串str。
public StringBuffer reverse()反转此StringBuffer。
StringBuffer delete(int startIndex, int endIndex)删除左闭右开的元素[startIndex, endIndex)。
public char charAt(int n )
public void setCharAt(int n ,char ch)修改
StringBuffer replace( int startIndex ,int endIndex, String str)修改多个字符
public int indexOf(String str)
public String substring(int start,int end)返回子串
public int length()返回长度
3. StringBuilder类

1)java.lang.StringBuilder代表可变的字符序列,它是线程不安全的,但执行方法效率要高于StringBuffer。

4. 与时间相关的类:

1)java.lang.System类下的public static long currentTimeMillis()方法
此方法适于计算时间差。

2)java.util.Date类
表示特定的瞬间,精确到毫秒。

构造方法详情
Date( )使用Date类的无参数构造方法创建的对象可以获取本地当前时间。
Date(long date)

常用方法详情
getTime()返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
toString()把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。

3)java.text.SimpleDateFormat
①该类比Date更国际化,它允许进行格式化(日期------>文本)、解析(文本------>日期)

②格式化:

SimpleDateFormat()默认的模式和语言环境创建对象
public SimpleDateFormat(String pattern)该构造方法可以用参数pattern指定的格式创建一个对象
public String format(Date date)用public SimpleDateFormat(String pattern)构造方法创造出的对象,该对象调用该方法格式化时间对象date

③解析:

public Date parse(String source)从给定字符串的开始解析文本,以生成一个日期。

④实例:

Date date = new Date();  //产生一个Date实例
//产生一个formater格式化的实例
SimpleDateFormat formater = new SimpleDateFormat();
System.out.println(formater.format(date));//打印输出默认的格式
SimpleDateFormat formater2 = new SimpleDateFormat("yyyy年MM月dd日 EEE HH:mm:ss");
System.out.println(formater2.format(date)); 
//实例化一个指定的格式对象
//按指定的格式输出
try {
	Date date2 = formater2.parse(20080808日 星期一 08:08:08");                    
	//将指定的日期解析后格式化按指定的格式输出
	System.out.println(date2.toString());
} catch (ParseException e) {
	e.printStackTrace();
}

4)java.util.Calendar(日历)类

Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
①获取Calendar实例的方法
法一:使用Calendar.getInstance()方法
法二:调用它的子类GregorianCalendar的构造器

方法
get(int field)通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND
public void set(int field,int value)
public void add(int field,int amount)
public final Date getTime()
public final void setTime(Date date)

③实例:

Calendar calendar = Calendar.getInstance();
// 从一个 Calendar 对象中获取 Date 对象
Date date = calendar.getTime();
//使用给定的 Date 设置此 Calendar 的时间
calendar.setTime(date);
calendar.set(Calendar.DAY_OF_MONTH, 8);
System.out.println("当前时间日设置为8后,时间是:" + calendar.getTime());
calendar.add(Calendar.HOUR, 2);
System.out.println("当前时间加2小时后,时间是:" + calendar.getTime());
calendar.add(Calendar.MONTH, -2);
System.out.println("当前日期减2个月后,时间是:" + calendar.getTime());
5. java.lang.Math类

1)其提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double型。
2)常用静态方法:

abs()绝对值
acos,asin,atan,cos,sin,tan三角函数
sqrt()平方根
pow(double a,doble b)a的b次幂
log()自然对数
exp()e为底指数
max(double a,double b)
min(double a,double b)
random()返回0.0到1.0的随机数
long round(double a)double型数据a转换为long型(四舍五入)
toDegrees(double angrad)弧度—>角度
toRadians(double angdeg)角度—>弧度
6. BigInteger类

1)构造器:

构造器
BigInteger(String val)

2)常用方法:

常用方法
public BigInteger abs()
public BigInteger add(BigInteger val)
public BigInteger add(BigInteger val)
public BigInteger subtract(BigInteger val)
public BigInteger multiply(BigInteger val)
public BigInteger divide(BigInteger val)
public BigInteger remainder(BigInteger val)
public BigInteger pow(int exponent)
public BigInteger[] divideAndRemainder(BigInteger val)
7. BigDecimal类

1)在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。BigDecimal类支持任何精度的定点数。

2)构造器

构造器
public BigDecimal(double val)
public BigDecimal(String val)

3)常用方法

常用方法
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

day19 Java反射机制

1. Class类

我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在在缓存区。那么这个运行时类本身就是一个Class的实例!
一、每一个运行时类只加载一次!
二、有了Class的实例以后,我们才可以进行如下的操作:
①创建对应的运行时类的对象
②获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解、…) *
③调用对应的运行时类的指定的结构(属性、方法、构造器)
④反射的应用:动态代理

2. 获取Class类的实例(四种方法)

1)法一:调用运行时类本身的.class属性

例:
Class clazz = String.class;

2)通过运行时类的对象获取

String str = new String();
Class clazz = str.getClass();

3)通过Class的静态方法获取。

Class clazz = Class.forNmae("java.lang.String");

4)(了解即可)通过类的加载器

ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz = classLoader.loadClass(“类的全类名”);
3. 类加载器ClassLoader

1)获取一个系统类加载器

ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();

2)获取系统类加载器的父类加载器,即扩展类加载器

classLoader2 = classloader1.getParent();

3)获取扩展类加载器的父类加载器,即引导类加载器

classLoader3 = classLoader2.getParent();

4)(掌握)类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流

设在类途径com.marvin.java下有一个jdbc.properties文件。现获取文件中的user和password的属性内容。

法一:
InputStream is = new FileInputStream(new File("jdbc.properties");
法二:
ClassLoader cl = this.getClass().getClassLoader();
InputStream is = cl.getResourceAsStream("com\\marvin\\java\\jdbc.properties");

(公共部分)
Properties pros = new Properties();
pros.load(is);
String user= pros.getProperty("user");
String password = pros.getProperty("password");

4. 创建类的对象

1)创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
要求::①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。

2)当要调用的是有参构造器时:
只要在操作的时候明确的调用类中的构造方法,并将参数传递进去之后,才可以实例化操作。步骤如下:
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)在Constructor类中存在一个方法:public T newInstance(Object … initargs),调用该方法创建一个相应构造器的实例。

例:调用指定的构造器,创建运行时类的对象。

设有一个Person类有Sting name和int age属性,且有构造方法:
private Person(String name, int age) {
	super();
	this.name = name;
	this.age = age;
}

则可以通过如下方式调用该带参构造器创建Person实例:
String className = "com.marvin.java.Person";
Class clazz = Class.forName(className);//此处要选择可能发生异常的处理方式
Constructor cons = clazz.getDeclaredConstructor(String.class,int,class);//此处要选择可能发生异常的处理方式
cons.setAccessible(true);
Person p = (Person)cons.newInstance("Marvin",23);
5. 通过反射获取类的完整结构

使用反射可获得:
1)实现的全部接口(interface)
public Class<?>[] getInterfaces():确定此对象所表示的类或接口实现的接口。

2)所继承的父类(Suprclass)
Class<? super T> getSuperclass():返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。

3)全部的属性(Field)
①public Field[] getFields() :返回此Class对象所表示的类或接口的public的Field。(包含其父类中声明的public方法)
②public Field[] getDeclaredFields() :返回此Class对象所表示的类或接口的全部Field。(任何权限修饰符修饰的都能获取,但不含父类中的)

Field类的方法中:
①public int getModifiers() :以整数形式返回此Field的修饰符
注:一般通过String str = Modifier.toString(实例.getModifiers());获取成真实的修饰符字符串。
②public Class<?> getType() :得到Field的属性类型
③public String getName() :返回Field的名称。

4)全部的方法(Method)
①public Method[] getDeclaredMethods():返回此Class对象所表示的类或接口的全部方法(任何权限修饰符修饰的都能获取,但不含父类中的)
②public Method[] getMethods() :返回此Class对象所表示的类或接口的public的方法(包含其父类中声明的public方法)

Method类中:
public int getModifiers():取得修饰符
注:一般通过String str = Modifier.toString(实例.getModifiers());获取成真实的修饰符字符串。
public Class<?> getReturnType():取得全部的返回值
public Class<?>[] getParameterTypes():取得全部的参数
public Class<?>[] getExceptionTypes():取得异常信息

5)全部的构造器(Constructor)
①public Constructor<T>[] getConstructors():返回此 Class 对象所表示的类的所有public构造方法。(包含其父类中声明的public方法)
②public Constructor<T>[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法。(任何权限修饰符修饰的都能获取,但不含父类中的)

获取得的Constructor类中:
①取得修饰符: public int getModifiers();
注:一般通过String str = Modifier.toString(实例.getModifiers());获取成真实的修饰符字符串。
②取得方法名称: public String getName();
③取得参数的类型:public Class<?>[] getParameterTypes();

6)Annotation注释相关
①get Annotation(Class<T> annotationClass)
②getDeclaredAnnotations()

7)泛型相关
①获取父类泛型类型:Type getGenericSuperclass()
②泛型类型:ParameterizedType
③获取实际的泛型类型参数数组:getActualTypeArguments()
例如:

1.获取父类的泛型
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();//获取带泛型的父类
ParameterizedType param = (ParameterizedType)type1;
Type[] ars = param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());

8)类所在的包
Package getPackage() :获取类所在的包名

6. 通过反射调用类中的指定方法、指定属性

1)调用指定属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
在Field类中,常用方法如下:

方法说明
public Object get(Object obj)取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value)设置指定对象obj上此Field的属性内容
public void setAccessible(true)访问私有属性时,让这个属性可见。(注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。)

2)调用指定方法
Object invoke(Object obj, Object … args)
注:
①Object 对应原方法的返回值,若原方法无返回值,此时返回null
②若原方法若为静态方法,此时形参Object obj可为null
③若原方法形参列表为空,则Object[] args为null
④若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

7. Java动态代理

1)Proxy类
①专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。

②静态方法:(提供用于创建动态代理类和动态代理对象)

方法说明
static Class<?> getProxyClass(ClassLoader loader, Class<?>… interfaces)创建一个动态代理类所对应的Class对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)直接创建一个动态代理对象

③例子:

//动态代理的使用,体会反射是动态语言的关键
interface Subject {
	void action();
}

// 被代理类
class RealSubject implements Subject {
	public void action() {
		System.out.println("我是在被代理类中执行的。");
	}
}

class MyInvocationHandler implements InvocationHandler {
	Object obj;// 实现了接口的被代理类的对象的声明

	// ①给被代理的对象实例化②返回一个代理类的对象
	public Object blind(Object obj) {
		this.obj = obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this);
	}
	//当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//method方法的返回值是returnVal
		Object returnVal = method.invoke(obj, args);
		return returnVal;
	}
}

public class TestProxy {
	public static void main(String[] args) {
		//1.被代理类的对象
		RealSubject real = new RealSubject();
		//2.创建一个实现了InvacationHandler接口的类的对象
		MyInvocationHandler handler = new MyInvocationHandler();
		//3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。
		Object obj = handler.blind(real);
		Subject sub = (Subject)obj;//此时sub就是代理类的对象
		
		sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值