JAVA集合框架提供了一套性能优良、使用方便的接口和类,它们存放于java.util包中。JAVA的集合类主要由Map接口和Collection接口派生而来。Collection接口有两个常用的子接口:List接口和Set接口。所以通常说JAVA集合框架由三大类接口构成。如下图:
1.List接口
Collection接口是最基本的集合接口,可以存储一组不唯一、无序的对象。而List接口继承自Collection接口,是有序的集合。用户可以通过索引访问List接口中的元素。List接口中允许存放重复的元素,也就是说List可以存放一组不唯一、但有序的对象。
List接口有两个常用的实现类:ArrayList和LinkedList
1.1 ArrayList类
ArrayList类对数组进行了封装,实现了长度可变的数组,和数组有相同的存储方式,在内存在分配连续的空间,所以被称为动态数组。但是他不等同于数组,他可以添加任何类型的数据,并且添加的数据都将转换成Object类型,而且只能添加同一类型的数据。
ArrayList类提供了很多方法用于操作数据:
public static void mai(String[] args){
List list = new ArrayList();
list.add("TOM");
list.add("JOSE");
list.add("JACK"); //向列表中添加元素。
System.out.println(list.contains("JIM")); //判断列表中是否有JIM这个元素。返回false.
list.remove(0);//将列表中第一个元素(TOM)删除。
list.set(0,"SAM");//将列表中第一个元素替换为SAM.
for(int i=0;i<list.size();i++){ //for循环遍历集合
String name = (String)list.get(i); //须强制类型转换,因为存储在集合中的数据都转换成了Object类型
System.out.println(name);
}
System.out.println(list.indexOf("JACK")); //返回JACK在集合中出现的索引值。
for(Object obj:list){ //foreach遍历集合
String name = (String)obj;
System.out.println(name);
}
list.clear();//清空list中的数据。
System.out.println(list.isEmpty());//判断list集合是否为空。
}
ArrayList的优点:因为它可以使用索引直接访问数据,所以他遍历元素和随机访问元素的效率比较高。
缺点:因为和数组的存储方式相同,在内存中分配了连续的空间,再添加和删除非尾部元素时会导致后面的元素移动,造成了操作性能低下。
1.2 LinkedList类
LinkedList采用了链表的存储方式,优点在于插入、删除元素时效率比较高;缺点是查找效率很低。当对数据添加和删除或修改比较多时,采用LinkedList存储数据。
LinkedList除包括ArrayList类所包含的方法外,还提供了以下方法:
Set接口是Collection接口的另外一个常用接口,他可以存储一组唯一、无序的对象。(不能保存重复的对象)
Set接口常用的实现类是HashSet
2.1 HashSet类
特点:⊙查找效率高
⊙HashSet类是非线程安全的
HashSet类常用的方法List中的方法基本相同,但是值得注意的是:HashSet类没有get()方法,无法通过get()方法取出每个对象,所以Set接口无法使用普通for循环遍历,只能使用foreach或者Iterator接口遍历。
示例:
//关键代码:
Student stu1 = new Student(001,"TOM");
Studnet stu2 = new Student(002,"JIM");
Set stuSet = new HashSet();
stuSet.add(stu1);
stuSet.add(stu2);
for(Object obj:stuSet){ //foreach遍历
Student student = (Student)obj;
System.out.println(student.getID()+" "+student.getName());
}
//也可以用Iterator接口遍历 Iterator接口的三个方法:iterator()方法获取迭代器、hasNext()方法判断是否有下一个元素、
// next()方法得到一个元素。
Iterator it = stuSet.iterator(); //iterator()方法获取迭代器,返回一个Iterator对象
while(it.hasNext()){ //hasNext()方法判断是否存在下一个可访问的元素,如果仍有元素可以迭代,返回true.
Student student = (Student)it.next(); //next()方法 返回访问的下一个元素
System.out.println(student.getID()+" "+student.getName());
}
2.2 TreeSet类
使用元素的自然顺序对元素进行排序,插入该 set 的所有元素都必须实现
Comparable
接口。Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序(升序),类的 compareTo 方法被称为它的自然比较方法。/*
TreeSet的性能比 HashSet差但是我们 在需要排序的时候可以用TreeSet 因为他是
自然排序也就是 升序
下面是TreeSet实现代码
这个类也似只能通过迭代器迭代元素
*/
import java.util.*;
class Test
{
public static void main(String []args)
{
TreeSet<Point> ts=new TreeSet<Point>() ;
ts.add(new Point(2,3));
ts.add(new Point(1,7));
ts.add(new Point(8,8));
ts.add(new Point(1,3));
ts.add(new Point(0,4));
Iterator i=ts.iterator(); //迭代器
while(i.hasNext())
{
System.out.println(i.next());
}
}
}
class Point implements Comparable<Point> //实现 Comparable 接口 插入到TreeSet集合中的元素必须实现
{
int x,y;
Point(int x,int y)
{
this.x=x;
this.y=y;
}
Point()
{
this.x=this.y=0;
}
public int compareTo(Point o) //实现Comparable中的 compareTo()方法
{
Point p=(Point)o;
int num=x>p.x?1:(x==p.x?0:-1) ;
if(num==0)
return y>p.y?1:(y==p.y?0:-1);
return num ;
}
public String toString()
{
return "x="+x+",y="+y;
}
}
3.Map接口
Map接口存储一组成对的键-值对象,提供了key到value的映射,通过key来检索。key不要求有序,但是不可以重复,而value不要求有序,但可以重复。
Map接口没有add()方法,常用的方法有:
put(key,value)方法 将相互关联的一个key与value放入集合,如果此Map中已经包含了该key与value,则旧值被替换。
remove(key)方法 删除与key相关联的映射,如果无此key,则返回null
get(key)方法 获得与key相关联的value
containsKey(key) 判断集合中是否存在key
containsValue(value) 判断集合中是否存在value
isEmpty() 判断集合中是否存在元素
clear() 清空集合中的所有元素
size() 返回集合中元素的数量,即该集合的长度
keySet() 获取所有key的元素
values() 获取所有value的集合
3.1 HashMap类
最常用的Map实现类是HashMap,优点是查询指定元素效率高。
示例:
//关键代码:
Student stu1 = new Student("张三","男");
Student stu2 = new Student("李四","女");
Map stus = new HashMap();
stus.put("Jack",stu1);
stus.put("Jose",stu2);
if(stus.containsKey("Jack")){ //containsKey()判断是否存在与key相关联的元素。
Student stu = (Student)stus.get("Jack");
System.out.println("Jack的中文名字是:"+stu.getName());
}
System.out.println("学生的英文名字分别是:");
for(Object obj : stus.keySet()){
System.out.println(obj.toString());
}
System.out.println("学生的详细信息是:");
for(Object obj:values()){ //foreach遍历 values()方法用于获取该集合中所有value的集合
Student student = (Student) obj;
System.out.println(student.getName()+" "+student.getSex());
}
//用iterator遍历如下:
Iterator iter = stus.values().iterator();
while(iter.hasNext()){
Student students = (Student)iter.next();
System.out.println(students.getName()+" "+students.getSex());
}
该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的
Comparator
进行排序,具体取决于使用的构造方法。示例:
- public class TestSort {
- public static void main(String[] args) {
- TreeMap map = new TreeMap();
- for(int i=0; i<3; i++) {
- String s = ""+(int)(Math.random()*1000);
- map.put(s,s);
- }
- map.put("abcd","abcd");
- map.put("Abc", "Abc");
- map.put("bbb","bbb");
- map.put("BBBB", "BBBB");
- map.put("北京","北京");
- map.put("中国","中国");
- map.put("上海", "上海");
- map.put("厦门", "厦门");
- map.put("香港", "香港");
- map.put("碑海", "碑海");
- Collection col = map.values();
- Iterator it = col.iterator();
- while(it.hasNext()) {
- System.out.println(it.next());
- }
- }
- }
- public class CollatorComparator implements Comparator {
- Collator collator = Collator.getInstance();
- public int compare(Object element1, Object element2) {
- CollationKey key1 = collator.getCollationKey(element1.toString());
- CollationKey key2 = collator.getCollationKey(element2.toString());
- return key1.compareTo(key2);
- }
- }
运行结果:
132
205
287
Abc
BBBB
abcd
bbb
上海
中国
北京
厦门
碑海
香港
4.Collections类操作集合
Collections 类是JAVA提供的一个集合操作工具类,它包含了大量的静态方法,用于实现对集合元素的排序、查找和替换等操作。
Collections和Collection是不同的,前者是集合的操作类,后者是集合接口。
4.1 对集合元素排序、查找
在JAVA中,如果想实现一个类的对象之间比较大小,那么这个类就要实现Comparable接口。此接口强行对实现它的每个类的对象进行整体排序,也称为类的自然排序。类的compareTo()方法用于比较此对象与指定对象的顺序。
int compareTo(Object obj);
实现Comparable接口的对象列表可以通过Collections.sort()方法(Arrays.sort()方法)进行自动排序。
而Collections.binarySearch()方法可以对集合元素进行查找。
示例:
关键代码:
public class Student implements Comparable{ //定义了学生类并实现了Comparable接口。
private int number = 0;
private String name;
private String gender;
public int getNumber(){
return number;
}
public void setNumber(int number){
this.number = number;
}
...省略name 、gender的get() set()方法
public int comparaTo(Object obj){ //重写了Comparable接口中的comparaTo(Object obj)方法
Student stu = (Student)obj;
if(this.number==stu.getNumber){
return 0;
}else if(this.number>stu.getNumber){
return 1;
}else{
return -1;
}
}
}
pubilc static void main(String[] args){
Studnet student1 = new Student();
studnet1.setNumber(5);
Studnet student2 = new Student();
studnet1.setNumber(3);
Studnet student3 = new Student();
studnet1.setNumber(2);
Studnet student4 = new Student();
studnet1.setNumber4);
Studnet student5 = new Student();
studnet1.setNumber(1);
ArrayList<Student> list = new ArrayList<Student>();
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
list.add(student5);
System.out.println("排序前:")
for(Object obj:list){ //foreach遍历
Studnet stu = (Student)obj;
System.out.println(stu.getNumber()+" "+stu.getName()+" "+stu.getGender());
}
Collections.sort(list); //使用Collections的sort()方法对list进行排序。
System.out.println("排序后:");
Iterator iterator = list.iterator(); //使用Iterator遍历
while(iterator.hasNext()){
Student stus = (Student)iterator.next();
System.out.println(stu.getNumber()+" "+stu.getName()+" "+stu.getGender());
//使用Collections的binarySearch()方法对list进行查找
int index = Collections.binarySearch(list,student2);
System.out.println("student2的索引是:"+index);
//使用Collections的fill()方法使用指定值替换列表中所有的元素;replaceAll()方法使用另一个值替换
// 列表中出现的所有指定元素。reverse()方法反转列表中元素的顺序。
Collections.reverse(list);
Collections.replaceAll(list,studnet1,student5);
}
}
5.泛型
将对象的类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。泛型的本质就是参数化类型。
创建集合时使用泛型指定集合中元素的类型,从集合中取出元素时无需进行强制类型转换。如果把非指定类型的元素放入集合时,会提示编译错误。
示例:
Map<String,Stduent> students = new HashMap<String,Student>();
students.put("Jack",student1);
students.put("Jose",student2);
for(String key:students.keySet()){//遍历key值
System.out.println(key);//key无需再强制类型转换
}
for(Student stu:students.values()){ //stu无需再强制类型转换
Sytem.out.println(stu.getName()+" "+stu.getSex())
}
Iterator it = studnets.iterator();
while(it.hasNext()){
Studnet stus = it.next();// it.next()获取到的对象无需再强制类型转换
System.out.println(stus.getName()+" "+suts.getSex());
}
学习泛型还需了解两个重要的概念:
a.参数化类型:参数化类型包含了一个类或者接口,以及实际的类型参数列表。
b.类型变量:是一种非限定性标识符,用来指定类、接口或者方法的类型。
二、JAVA中常用的实用类
1.JAVA API
API除了有“应用程序编程接口”的意思外,还特指API帮助文档。
API提供了以下常用的包:
java.lang 包含了java程序的基础类和接口。如包装类、Math类、String类等
java.util 包含了系统辅助类或者工具类。如Collection、list、Map等集合类等
java.io 包含了输入输出有关的类。如InputStream \OutputStream 、Reader\Writer类等
java.net 包含了与网络有关的类。如:Socket、ServerSocket类等
java.sql 包含了与数据库有关的类。如:Connection、Statement类等
2.枚举类
枚举类是由一组固定的常量组成的类,使用关键字enum定义。
例如定义标识性别的枚举类:
public enum Genders{ //使用关键字enum而且修饰符一般为public
Male,Female //各个常量之间用","隔开
}
示例:
public enum Week{ //定义枚举类
MON,TUE,WED,THR,FRI,SAT,SUN
}
class WeekDemo{
public void doWhat(Week day){
switch(day){
case MON:
case TUE:
case WED:
case THU:
case FRI:
System.out.println("工作日,努力工作");
break;
case SAT:
case SUN:
System.out.println("休息日,钓鱼、看电影");
break;
default:
System.out.println("一个星期就7天");
}
}
public static void main(String[] args){
WeekDemo wd = new WeekDemo();
wd.doWhat(Week.THU);
wd.doWhat(Week.SAT);
}
}
在程序中使用枚举类的好处:
a.是代码易于维护,有助于确保为变量指定合法、期望的值。
b.便于输入,使用枚举赋值,只需在枚举名后面输入“.”就能将所有枚举值显示出来。
3.包装类
JAVA语言是面向对象的,但JAVA中的基本数据类型却不是面向对象的,为了解决这个不足,JAVA为8个基本数据类型都分别设计了一个对应的类,称为包装类。
包装类的主要用途有两个:
a.包装类作为和基本数据类型对应的类存在,方便对象的操作。
b.包装类包含了每种基本数据类型的相关属性,如最大、最小值以及相关的操作方法。
包装类和基本数据类型的转换
1.基本数据类型转换成包装类
a>使用包装类的两个构造方法
public Type(type value)
public Type(String value)
使用new关键字将一个基本数据类型的值包装成一个对象。如,要把int包装成Integer类
int x = 21;
Integer intX = new Integer(21); //第一种构造方法public Type(type value)
Integer intX = new Integer("21");//第二种构造方法public Type(String value)
char y = w;
Character charY = new Character('w');//正确
Character charY = new Character("w"); //这种形式是错误的,因为char y是字符,不是字符串
b>使用包装类的方法valueOf()
如:
Integer intX = Integer.valueOf("21"); //正确
Character charY = Character.valueOf("w");//错误,y是char类型不是String类型
Character charY = Character.valueOf('w');正确
2.包装类转换成基本数据类型
方法:public type typeValue(); 如:byteValue()、charValue()分别返回byte、char值。
Integer integer = new Integer(25);
int intX = integer.intValue()//调用Integer包装类的intValue()方法
3.基本数据类型和包装类自动转换
JAVA5.0之后,实现了包装类和基本数据类型的自动转换,编译器会自动完成。
如:
Integer intObject = 5;//基本数据类型转换成包装类
int intValue = intObject; //包装类转换成基本数据类型
注:包装类对象只有在基本数据类型需要用对象来表示时才使用,并不是用来取代基本数据类型的。否则相互转换会增加系统的额外负担。
4.Math类
java.lang.Math类是一个final类,提供了一些基本数学运算和几何运算的方法。
Math类常见的方法有:
static double abs(double a) 返回double值得绝对值。如:Math.abs(-3.3);返回3.3
static double max(double a,double b) 返回最大值。如:Math.max(2.5,6.3);返回6.3
static double random();随机返回一个double值,该值大于等于0.0且小于1.0 (>=0.0&&<1.0)
如:随机产生0-9的数
int number = (int)(Math.random()*10);
5.String类
String类提供了很多方法,如,获取字符串的长度,比较、连接、提取、替换等等。
a>length()返回字符串的长度
b>equals()比较两个字符串的值是否相同。str1.equals(str2);
注:java中"=="和equals()方法应用于字符串时,所判断的内容是不同的。"=="判断的是两个字符串在内存中的地址是否相同,也就是判断是否是同一个对象,而equals()判断的是两个字符串的值是否相等。用equals()比较两个字符串"java"和"JAVA"时是不相等的,但他们都是同一门课程,因此需要使用另一个方法equalsIgnoreCase()方法。这个方法比较字符串时会忽略字符的大小写。
c>equalsIgnoreCase()//忽略大小写
toLowerCase()//转换成小写
toUpperCase() //转换成大写
d>concat()方法//连接字符串。如:str1.concat(str2);返回一个新的字符串str1str2
连接字符串也可以用"+"来连接
e> indexOf(int ch)
indexOf(String str) //搜索第一个出现的字符ch(字符串str)
lastIndexOf(int ch)
lastIndexOf(String str)//搜索最后一个出现的字符ch(字符串str)
substring(int index)//提取从索引位置开始的字符串部分
substring(beginindex,endindex)//提取两个索引之间的字符串部分
trim()//返回一个前后不含任何空格的字符串副本
示例:判断邮箱名称和JAVA文件名称是否合法
public class Test{
public static void main(String[] args){
boolean fileflag = false;//文件信号量标识
boolean mainflag = false;//邮箱标识
Scanner input = new Scanner(System.in);
String filename = input.next();
String mailname = input.next();
//检查JAVA文件名是否合法
int index = filename.lastIndexOf(‘.’);//"."的位置
if(index!=-1&&index!=0&&filename.substing(index+1,filename.length()).equals("java")){
fileflag = true;
}else{
System.out.println("文件名无效");
}
//检查邮箱格式是否合法
if(mailname.indexOf(‘@’)!=-1&&mailname.indexOf(‘@’)!=0&&mailname.indexof(‘.’)>mailna
me.indexOf(’@‘)){
mailflag = true;
}else{
System.out.println("无效的邮箱名");
}
if(fileflag&&mailflag){
System.out.println("提交成功");
}else{
System.out.prinltn("提交失败");
}
}
}
f> split()//拆分字符串
示例:关键代码:
String words ="abc+def+ghi+jkl";
String[] word = new String[10];
word = words.split("+");//将字符串按"+"拆分
for(String str:word){
System.out.println(str);
}
6.StringBuffer类和StringBuilder类
StringBuffer类的声明和初始化
StringBuffer sb = new StringBuffer("浪子回头");
StringBuffer常用的方法
a> toString() //转换为字符串类型
b> append() //追加字符串 str.append(args); 该方法不同于String的concat()方法的是StringBuffer类可
以将任何类型的值追加到字符串后面。
示例:
//关键代码:
StringBuffer sb = new StringBuffer("浪子回头");
StringBuffer sb2 = sb.append("金不换");
int num = 100000000;
StringBuffer sb3 = sb2.append(num);//追加了一个int类型的整数
System.out.println(sb3);
运行结果:浪子回头金不换100000000
c> insert(index,args)方法 将参数插入到指定的位置后返回,参数可以是任何类型。
示例:从后往前每隔3位插入","
String num = "1234567890";
StringBuffer sb = new StringBuffer(num);
for(int i=sb.length()-3;i>0;i=i-3){
sb.insert(i,',');
}
System.out.prinltn(sb.toString());
StringBuilder类
StringBuilder类是一个可变的字符序列,此类提供一个与StringBuffer兼容的API,它比StringBuffer实
现快。
7.String 、StringBuffer、StringBuilder的区别
String:字符串常量
String 是不可变的对象,在每次对String进行改变的时候其实等于生成了一个新的String对象,然后
指向新的String对象地址。
StringBuffer: 字符串变量
StringBuffer是可变的字符串,在每次对StringBuffer对象进行改变时,会对StringBuffer自身进行
操作,而不会形成新的对象。在字符串连接操作中,Stringbuffer比String效率
StringBuilder: 字符串变量
StringBuilder它与StringBuffer类等价,区别在于StringBuffer类是线程安全的,StringBuilder类是
单线程的,不提供同步。
8.日期和时间类
Date类、Calendar类、SimpleDateFormat类等
Date date = new Date();//获取系统当前时间
Calendar类是Date类的增强版,它是个抽象类,可以通过静态方法getInstance()方法获得Calendar对象
SimpleDateFormat类用来格式化时间
示例:关键代码:
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
System.out.println("当前时间为:"+sdf.format(date));
输出结果:当前时间为:2013年8月30日 14:47:34
Calendar示例关键代码:
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR)+"年"+(c.get(Calendar.MONTH)+1)+"月"
+c.get(Calendar.DAY_OF_MONTH)+"日");
Ststem.out.println("星期"+(c.get(Calendar.DAY_OF_WEEK)-1);
9.Random类
Random类用于生成随机数。
构造方法:Random()/Random(long seed)种子随机数生成器
示例:生成10个10以内大于或等于0的整数
Random rand = new Random(100);
Random rand2 = new Random(100)
for(int i=0;i<10;i++){
int num = rand.nextInt(10);
System.out.println("第"+(i+1)+"个随机数为:"+num);
}
for(int i=0;i<10;i++){
int num2 = rand2.nextInt(10);
System.out.println("第"+(i+1)+"个随机数为:"+num2);
//两个随机数生成器用同一个种子,生成的随机数相同。
示例:随机购买双色球
import java.util.HashSet;
输入输出流是用来操作数据的读写的,而数据一般都是保存在文件File当中的。
1. File类用来操作文件或目录
File类常用的方法有:
boolean exists()//检测文件是否存在
getAbsolutePath()//返回文件的绝对路径
getName()//返回文件的名称
delete()//删除指定的文件
createNewFile()//创建空文件,不创建文件夹
isDirectory()//测试此File对象表示的是否是目录
mkdir()//创建由该File对象表示的目录
mkdirs()//创建包括父目录的目录
lastModified()//返回文件的最后修改日期
length()//返回文件的大小,单位:字节
示例:
import java.io.File;
结果:
File name:test.txt File create Time: 2013-08-30 16:08
流按流向分为输入流和输出流,输入流有字节流(InputStream)和字符流(Reader),输出流也有字节流
(OutputStream)和字符流(Writer)。
示例:用字节流读取文件(读写数组的大小会影响数据的完整性,会发生多读多写现象)
import java.io.FileInputStream;
示例2:用字符流读写文件 (Reader\Writer)
FileInputStream fis = new FileInputStream("d:\\Collection.java");
DataInputStream\DataOutputStream搭配使用可以按照与平台无关的方式从流中读写基本数据类型的数据
其中提供了readUTF()和writeUTF()方法可以读写UTF-8字符编码的数据。
3.序列化保存对象信息和反序列化获取对象信息
序列化:就是将对象的状态存储到特定介质(硬盘、网络)中的过程
JAVA中只有实现了Serializable接口的类的对象才能被序列化。JDK中有些类库如String类、包装类、Date
类等都实现了Serializable接口。
对象序列化的步骤分两大步:
a>创建一个对象输出流(ObjectOutputStream),它可以包装一个其他类型的输出流,如文件输出流
(FileOutputStream)
b>通过对象输出流的wirteObject()方法写对象,也就是输出可序列化对象。
反序列化:就是从介质中获取对象信息,然后重新构建为对象的过程
反序列化的步骤分两大步:
a> 创建一个对象输入流(ObjectInputStream),可以包装一个输人流,如文件输入流(FileInputStream)
b> 通过对象输入流的readObject()方法读取对象,返回一个Object类型的对象。
序列化和反序列化示例:
new ObjectOutputStream(new FileOutputStream("D:\\Serializable.txt"));
ArrayList<Student> list2 = (ArrayList<Student>) ois.readObject();
反序列化结果:
Students massage is:
序列化的算法规则:
a> 所有保存到磁盘中的对象都有一个序列号
b> 当程序试图序列化一个对象时,会先检查是否已经被序列化,只有序列化后的对象才能被转换成字节输出
c> 如果对象已经被序列化,则程序直接输出一个序列化编号,而不重新序列化。
4.1 定义:JAVA中的反射是指在运行状态中,动态获取信息以及动态调用对象方法的功能。
4.2 JAVA反射有三个动态性质:
a>运行时生成对象实例
b>运行期间调用方法
c>运行时更改属性
4.3 JAVA反射常用API
a> Class类:反射的核心类,反射所有的操作都是围绕该类生成的。通过该类可以获取类的属性、方法
b> Field类:表示类的属性,可以获取和设置类中的属性值
c> Method类:表示类的方法,可以获取类中方法的信息,或者执行方法
d> Constructor类:表示类的构造方法
4.4 使用反射的基本步骤:
a> 获得需要操作的类的Class对象
b> 调用Class的方法获取Field、Method等对象
c> 使用反射API进行操作
1>获取Class对象有3中方式
调用对象的getClass()方法
如:Student stu = new Student();
Class cls = stu.getClass();
调用类的Class属性 //通常使用该方法获取Class对象
如:Class cls = Student.class;
使用Class类的forName()方法
如:Class cls = Class.forName("java.test.Student");//必须写路径全称,完整的包名
2>从Class对象获取信息
访问Class对应的类的构造方法
访问Class对应的类的方法
访问Class对应的类的属性
3>通过反射创建对象
使用Class对象的newInstance()方法创建对象
如: Class cls = Student.class;
Student stu = (Student)cls.newInstance() //使用默认构造方法实例化一个学生对象
使用Consstructor对象创建对象
如:
Class cls = Student.class;
Constructor con = cls.getConstructor(String.class,String.class);//指定构造方法
Student stu = (Student)con.newInstance("Tom","female"); //使用指定构造方法创建对象
4>通过反射访问类的属性
使用Field对象可以获取对象的属性,并且可以对获取到的属性进行取值或赋值操作
Student stu = new Student();
Class cls = Student.class;//获取Student类的Class对象
Field name = cls.getDeclaredField("name");//getDeclearedField()方法可获取各访问级别的属性
name.setAccessible(true);//设置 通过反射访问该属性时取消权限检查
name.set(stu,"Jack");//调用set()方法给stu对象重新赋值
Field age = cls.getDeclearedField("age");
age.setAccessible(true);
age.setInt(stu,30);//这里调用的是setInt()方法,age为int类型,name 为String,所以用set()
5>通过反射访问类的方法
使用Method对象的invoke()方法可以调用对象的方法
Student stu = new Student();
Class cls = Student.class;
Method met1 = cls.getMethod("setName",String.class);//得到Student类的setName()方法
met1.invoke(stu,"TOM");//通过invoke()方法调用setName()方法为stu对象的name赋值
Method met2 = cls.getMethod("getName",null)//null表示该方法无参数
Object o = met2.invoke(stu,null);//invoke()调用getName()方法得到stu对象的name值
System.out.println(o.toString());
6>使用Array类动态创建和访问数组
Array类的对象可以代表所有的数组。程序可以通过使用Array类来动态创建数组、操作数组元素
//创建一个元素类型为String,长度为10的数组
Object arr = Array.newInstance(String.class,10); //使用Array.newInstance()动态创建数组
//依次向数组中的元素赋值
Array.set(arr,0,"work");
Array.set(arr,1,"study");
//从数组中取出元素的值
Object o1 = Array.get(arr,0);
Object o2 = Array.get(arr,1);
5.多线程
5.1 进程
进程是程序的一次动态执行过程,它对应了从代码加载、执行、结束的一个完整过程。
进程的特点是:
进程是系统运行程序的基本单元。
每一个进程都有自己独立的内存空间和系统资源。
每一个进程的内部数据和状态都是完全独立的。
5.2 线程
线程是进程中执行运算的最小单位,一个进程在执行过程中可以产生多个线程,用来完成不同的工作称之为
多线程。
5.3 创建线程的两种方法:
继承Thread类:它的缺点是继承了Thread类的线程类不能再继承别的类。
如:public class MyThread extends Thread{
public void run(){
//重写父类Thread的run()方法
}
}
public class Test{
MyThread mt = new MyThread();//实例化线程对象
mt.start(); //启动线程
}
实现Runnable接口:当一个线程继承了另一个类时,就只能用实现Runnable接口来创建线程。
如:public class MyThread implements Runnable{
public void run(){
//同样要重写Runnable接口中的run()方法
}
}
public class Test{
new Thread(new MyThread()).start();//实例化并启动线程。
}
5.4 线程的状态
线程的生命周期可以分为4个阶段,即线程的4种状态:新生状态、可运行状态、阻塞状态、死亡状态。
5.5 线程的调度
a>线程的调度按线程的优先级进行调度。优先级高的先执行。
b>线程的优先级用1-10表示,1表示最高优先级,默认优先级为5 。线程的优先级可以通过setPriority()方法
更改。如myThread.setPriority(3);设置优先级为3。
c> join()方法使当前线程暂停执行,等待调用该方法的线程执行完毕后再继续执行。
Thread.currentThread().getName()方法可以获取当前线程的名称。
示例:用join()的方法实现两个线程间的数据传递
class MyThread implements Runnable{
d> sleep()方法可以阻塞线程 。如thread.sleep(1000)//线程睡眠1秒
5.6 线程同步
当两个或多个线程需要访问同一资源时,确保该资源在同一时刻只能被一个线程使用的方式称为线程同步。
实现线程同步有两种方式:同步方法、同步代码块。这两中方式都使用synchronized关键字实现。5.0以后还提
供了Lock和Condition接口用来实现线程同步。
JAVA提供了很多方法实现线程间的通信:
synchronized : wait()、notify()、notifyAll()
Lock : lock()、unlock()
Condition : await()、signal()、signalAll()
示例:使用synchronized 同步方法
/**
+"..............生产者生产了............. "+this.name);
输出结果:
Thread-1..............生产者生产了............. 商品1
示例2:使用synchronized 同步代码块
示例3:使用Lock、Condition接口实现线程同步通信
+"..............生产者生产了............. "+this.name);
+"....消费者消费了.... "+this.name);
6.Socket网络编程技术
6.1 TCP协议的Socket编程
java.net包中的Socket类、ServerSocket类,分别用来实现双向连接的客户端和服务器端,他们基于TCP协
议进行工作的,工作的过程如同打电话,双方都接通了才能开始通话。Socket借助数据流来完成数据的传递。
示例:图片的并发上传。
需要三个类:Server类、ServerThread线程类、Client类
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
示例2:基于TCP协议的文件上传下载
6.2 基于UDP协议的Socket编程
利用DatagramPacket对象封装和处理数据,利用DatagramSocket对象发送和接受数据。
示例:
import java.io.IOException;
//客户端
import java.io.IOException;