目录
6 异常处理
1.体系结构
java.lang.Object
|----java.lang.Throwable
|-------java.lang.Error:错误,java程序对此无能为力,不显式的处理
|-------java.lang.Exception:异常。需要进行处理
|------RuntimeException:运行时异常
|-----ArrayIndexOutOfBoundsException/NullPointerException/ArithmeticException/ClassCastException
|------非RuntimeException:编译时异常
2.因为java程序分为javac.exe和java.exe两个过程,在每个过程中,都有可能出现异常。故分为编译时异常、运行时异常
2.1 对于运行时异常比较常见,可以不显式的来处理。
2.2 对于编译时异常,必须要显式的处理
编译时异常,不是说有异常才处理,而是存在异常的隐患,必须在编译前,提示程序,万一出现异常,如何处理!2.如何处理异常?
java 中的“抓抛模型”
* 1."抛":当我们执行代码时,一旦出现异常,就会在异常的代码处生成一个对应的异常类型的对象,并
* 将此对象抛出。(自动抛出 / 手动抛出)
* >一旦抛出此异常类的对象,那么程序就终止执行
* >此异常类的对象抛给方法的调用者。
* 2."抓":抓住上一步抛出来的异常类的对象。如何抓?即为异常处理的方式
* java 提供了两种方式用来处理一个异常类的对象。
* 处理的方式一:
* try{
* //可能出现异常的代码
* }catch(Exception1 e1){
* //处理的方式1
* }catch(Exception2 e2){
* //处理的方式2
* }finally{
* //一定要执行的代码
* }
* 注:1.try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
* 2.finally是可选的。
* 3.catch语句内部是对异常对象的处理:
* >getMessage(); printStackTrace();
* 4.可以有多个catch语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足
* 就执行catch中的代码。执行完,就跳出其后的多条catch语句
* 5.如果异常处理了,那么其后的代码继续执行。
* 6.若catch中多个异常类型是"并列"关系,孰上孰下都可以。
* 若catch中多个异常类型是"包含"关系,须将子类放在父类的上面,进行处理。否则报错!
* 7.finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句。
* 8.try-catch是可以嵌套的。
处理方式二:
在方法的声明处,显式的使用throws + 异常类型
public void method1() throws Exception1 e1,Exception2 e2{
//可能出现异常(尤其是编译时异常,一定要处理)
}
public void method2() throws Exception1 e1,Exception2 e2{
method1();
}public void method3(){
try{
method2();
}catch(Exception1 e1){
System.out.println(e1.getMessage());
}catch(Exception2 e2){
System.out.println(e2.getMessage());
}}
public static void main(String[] args){
对象1.method3();//不会再出现上述的Exception1和Exception2的异常!
}
3.如何手动的抛出一个异常?
在方法的内部,可以使用 throw + 异常类对象,来手动的抛出一个异常!//比较两个圆的半径的大小。
public int compareTo(Object obj) throws Exception{
if(this == obj){
return 0;
}
else if(obj instanceof Circle){
Circle c = (Circle)obj;
if(this.radius > c.radius){
return 1;
}else if(this.radius == c.radius){
return 0;
}else{
return -1;
}
}else{
//return -2;
//手动的抛出一个异常
//throw new Exception("传入的类型有误!");
//throw new String("传入的类型有误!");
throw new MyException("传入的类型有误!");
}
}
4.如何自定义一个异常类?
>手动的抛出一个异常,除了抛出的是现成的异常类的对象之外,还可以抛出一个自定义的异常类的对象!
>如何自定义一个异常类呢?
//1.自定义的异常类继承现有的异常类
//2.提供一个序列号,提供几个重载的构造器
public class MyException extends Exception{
static final long serialVersionUID = -70348975766939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
5.“5个关键字搞定异常处理!” 其中,要区分:throw与throws的区别?
7 集合
1.对象的存储:①数组(基本数据类型 & 引用数据类型) ②集合(引用数据类型)
>数组存储数据的弊端:长度一旦初始化以后,就不可变;真正给数组元素赋值的个数没有现成的方法可用。
2.集合框架
Collection接口 :方法:①add(Object obj),addAll(Collection coll),size(),clear(),isEmpty();
②remove(Object obj),removeAll(Collection coll),retainAll(Collection coll),equals(Object obj),contains(Object obj)
containsAll(Collection coll),hashCode()
③ iterator(),toArray();
* |------List接口:存储有序的,可以重复的元素.---相当于“动态”数组
>新增的方法:删除remove(int index) 修改set(int index,Object obj) 获取get(int index)插入add(int index,Object obj)
>添加进List集合中的元素(或对象)所在的类一定要重写equals()方法
* |------ArrayList(主要的实现类)
|------LinkedList(更适用于频繁的插入、删除操作)
|------Vector(古老的实现类、线程安全的,但效率要低于ArrayList)
* |------Set接口:存储无序的,不可重复的元素。---相当于高中的“集合”概念
>Set使用的方法基本上都是Collection接口下定义的。
>添加进Set集合中的元素所在的类一定要重写equals() 和 hashCode()。要求重写equals() 和 hashCode()方法保持一致。
>1.无序性:无序性!= 随机性。真正的无序性,指的是元素在底层存储的位置是无序的。
>2.不可重复性:当向Set中添加进相同的元素的时候,后面的这个不能添加进去。
* |------HashSet(主要的实现类)
|------LinkedHashSet(是HashSet的子类,当我们遍历集合元素时,是按照添加进去的顺序实现的;频繁的遍历,较少的添加、插入操作建议选择此)
|------TreeSet(可以按照添加进集合中的元素的指定属性进行排序)
>要求TreeSet添加进的元素必须是同一个类的!
>两种排序方式:自然排序:①要求添加进TreeSet中的元素所在的类implements Comparable接口
②重写compareTo(Object obj),在此方法内指明按照元素的哪个属性进行排序
③向TreeSet中添加元素即可。若不实现此接口,会报运行时异常
定制排序:①创建一个实现Comparator接口的实现类的对象。在实现类中重写Comparator的compare(Object o1,Object o2)方法
②在此compare()方法中指明按照元素所在类的哪个属性进行排序
③将此实现Comparator接口的实现类的对象作为形参传递给TreeSet的构造器中
④向TreeSet中添加元素即可。若不实现此接口,会报运行时异常
>要求重写的compareTo()或者compare()方法与equals()和hashCode()方法保持一致。
Map接口:存储“键-值”对的数据 ----相当于高中的“函数y = f(x)” (x1,y1) (x2,y2)
>key是不可重复的,使用Set存放。value可以重复的,使用Collection来存放的。一个key-value对构成一个entry(Map.Entry),entry使用Set来存放。
>添加、修改 put(Object key,Object value) 删除remove(Object key) 获取get(Object key) size() / keySet() values() entrySet()
* |-----HashMap:主要的实现类,可以添加null键,null值
|-----LinkedHashMap:是HashMap的子类,可以按照添加进Map的顺序实现遍历
|-----TreeMap:需要按照key所在类的指定属性进行排序。要求key是同一个类的对象。对key考虑使用自然排序 或 定制排序
|-----Hashtable:是一个古老的实现类,线程安全的,不可以添加null键,null值不建议使用。
|-----子类:Properties:常用来处理属性文件Iterator接口:用来遍历集合Collection元素
Collections工具类:操作Collection及Map的工具类,大部分为static的方法。
附:Properties的使用
Properties pros = new Properties();
pros.load(new FileInputStream(new File("jdbc.properties")));
String user = pros.getProperty("user");
System.out.println(user);
String password = pros.getProperty("password");
System.out.println(password);
8 泛型
1.泛型在集合中的使用(掌握)
2.自定义泛型类、泛型接口、泛型方法(理解 --->使用)
3.泛型与继承的关系
4.通配符
1.在集合中不使用泛型
public void test1(){
List list = new ArrayList();
list.add(89);
list.add(87);
list.add(67);
//1.没有使用泛型,任何Object及其子类的对象都可以添加进来
list.add(new String("AA"));
for(int i = 0;i < list.size();i++){
//2.强转为int型时,可能报ClassCastException的异常
int score = (Integer)list.get(i);
System.out.println(score);
}
}
2.在集合中使用了泛型
public void test2(){
List<Integer> list = new ArrayList<Integer>();
list.add(78);
list.add(87);
// list.add("AA");
// for(int i = 0;i < list.size();i++){
// int score = list.get(i);
// System.out.println(score);
// }
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}public void test3(){
Map<String,Integer> map = new HashMap<>();
map.put("AA", 78);
map.put("BB", 87);
map.put("DD", 98);
Set<Map.Entry<String,Integer>> set = map.entrySet();
for(Map.Entry<String,Integer> o : set){
System.out.println(o.getKey() + "--->" + o.getValue());
}
}3.自定义泛型类:应用
public class DAO<T> {
public void add(T t){
//....
}
public T get(int index){
return null;
}
public List<T> getForList(int index){
return null;
}
public void delete(int index){
}
}public class CustomerDAO extends DAO<Customer>{
}
public class TestCustomerDAO {
public static void main(String[] args) {
CustomerDAO c = new CustomerDAO();
c.add(new Customer());
c.get(0);
}
}
【注意点】
1.对象实例化时不指定泛型,默认为:Object。
2.泛型不同的引用不能相互赋值。
3.加入集合中的对象类型必须与指定的泛型类型一致。
4.静态方法中不能使用类的泛型。
5.如果泛型类是一个接口或抽象类,则不可创建泛型
类的对象。
6.不能在catch中使用泛型
7.从泛型类派生子类,泛型类型需具体化
4.泛型与继承的关系
A类是B类的子类,G是带泛型声明的类或接口。那么G<A>不是G<B>的子类!5.通配符:?
A类是B类的子类,G是带泛型声明的类或接口。则G<?> 是G<A>、G<B>的父类!
①以List<?>为例,能读取其中的数据。因为不管存储的是什么类型的元素,其一定是Object类的或其子类的。
①以List<?>为例,不可以向其中写入数据。因为没有指明可以存放到其中的元素的类型!唯一例外的是:null6*. List<? extends A> :可以将List<A>的对象或List<B>的对象赋给List<? extends A>。其中B 是A的子类
? super A:可以将List<A>的对象或List<B>的对象赋给List<? extends A>。其中B 是A的父类
9 枚举类和注解
一、枚举类
1.如何自定义枚举类。 枚举类:类的对象是有限个的,确定的。
1.1 私有化类的构造器,保证不能在类的外部创建其对象
1.2 在类的内部创建枚举类的实例。声明为:public static final
1.3 若类有属性,那么属性声明为:private final 。此属性在构造器中赋值。
2.使用enum关键字定义枚举类
>2.1其中常用的方法:values() valueOf(String name);
>2.2枚举类如何实现接口 :①让类实现此接口,类的对象共享同一套接口的抽象方法的实现。
①让类的每一个对象都去实现接口的抽象方法,进而通过类的对象调用被重写的抽象方法时,执行的效果不同public class TestSeason1 {
public static void main(String[] args) {
Season1 spring = Season1.SPRING;
System.out.println(spring);
spring.show();
System.out.println(spring.getSeasonName());
System.out.println();
//1.values()
Season1[] seasons = Season1.values();
for(int i = 0;i < seasons.length;i++){
System.out.println(seasons[i]);
}
//2.valueOf(String name):要求传入的形参name是枚举类对象的名字。
//否则,报java.lang.IllegalArgumentException异常
String str = "WINTER";
Season1 sea = Season1.valueOf(str);
System.out.println(sea);
System.out.println();
Thread.State[] states = Thread.State.values();
for(int i = 0;i < states.length;i++){
System.out.println(states[i]);
}
sea.show();
}
}
interface Info{
void show();
}
//枚举类
enum Season1 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 final String seasonDesc;
private Season1(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season [seasonName=" + seasonName + ", seasonDesc="
+ seasonDesc + "]";
}
// public void show(){
// System.out.println("这是一个季节");
// }
}
二、注解Annotation
1.JDK提供的常用的三个注解
@Override: 限定重写父类方法, 该注释只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告2.如何自定义注解
以SuppressWarnings为例进行创建即可3.元注解:可以对已有的注解进行解释说明。
Retention: SOURCE CLASS RUNTIME
Target:
Documented:javadoc
Inherited
10 IO流
1.java.io包下
File类:java程序中的此类的一个对象,就对应着硬盘中的一个文件或网络中的一个资源。
File file1 = new File("d:\\io\\helloworld.txt");
File file2 = new File("d:\\io\\io1");
>1.File既可以表示一个文件(.doc .xls .mp3 .avi .jpg .dat),也可以表示一个文件目录!
>2.File类的对象是与平台无关的。
>3.File类针对于文件或文件目录,只能进行新建、删除、重命名、上层目录等等的操作。如果涉及到访问文件的内容,File
是无能为力的,只能使用IO流下提供的相应的输入输出流来实现。
>4.常把File类的对象作为形参传递给相应的输入输出流的构造器中!
2.IO 流的结构
3.IO流的划分
1) 按照流的流向的不同:输入流 输出流 (站位于程序的角度)
2) 按照流中的数据单位的不同:字节流 字符流 (纯文本文件使用字符流 ,除此之外使用字节流)
3) 按照流的角色的不同:节点流 处理流 (流直接作用于文件上是节点流(4个),除此之外都是处理流)4.重点掌握
* 抽象基类 节点流(文件流) 缓冲流(处理流的一种,可以提升文件操作的效率)
* InputStream FileInputStream (int read(byte[] b)) BufferedInputStream (int read(byte[] b))
* OutputStream FileOutputStream (void write(b,0,len)) BufferedOutputStream (flush()) (void write(b,0,len))
* Reader FileReader (int read(char[] c)) BufferedReader (readLine()) (int read(char[] c))或String readLine()
* Writer FileWriter (void write(c,0,len)) BufferedWriter (flush()) (void write(c,0,len)或void write(String str))
注: 1.从硬盘中读入一个文件,要求此文件一定得存在。若不存在,报FileNotFoundException的异常
2.从程序中输出一个文件到硬盘,此文件可以不存在。若不存在,就创建一个实现输出。若存在,则将已存在的文件覆盖
3.真正开发时,就使用缓冲流来代替节点流
4.主要最后要关闭相应的流。先关闭输出流,再关闭输入流。将此操作放入finally5.其它的流
1.转换流:实现字节流与字符流之间的转换
InputStreamReader:输入时,实现字节流到字符流的转换,提高操作的效率(前提是,数据是文本文件) ===>解码:字节数组--->字符串
OutputStreamWriter:输出时,实现字符流到字节流的转换。 ===>编码: 字符串---->字节数组
例子:从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序。2.标准的输入输出流
System.in: The "standard" input stream:从键盘输入数据
System.out:The "standard" output stream:从显示器输出数据3.打印流 (都是输出流) PrintStream(处理字节) PrintWriter(处理字符)
可以使用System.setOut(PrintStream p)重新设置一下输出的位置。
PrintStream p = new PrintStream(new FileOutputStream("hello.txt"),true);
4.数据流(处理基本数据类型、String类、字节数组)
DataInputStream DataOutputStream
5.对象流(用来处理对象的)
>对象的序列化机制:允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,
或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象
ObjectInputStream(Object readObject();) ObjectOutputStream (void writeObject(Object obj))
如何创建流的对象:ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("person.txt")));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("person.txt")));
实现序列化机制的对象对应的类的要求:①要求类要实现Serializable接口②同样要求类的所有属性也必须实现Serializable接口
③ 要求给类提供一个序列版本号:private static final long serialVersionUID;
④属性声明为static 或transient的,不可以实现序列化6.随机存取文件流:RandomAccessFile
6.1既可以充当一个输入流,又可以充当一个输出流:public RandomAccessFile(File file, String mode)
6.2支持从文件的开头读取、写入。若输出的文件不存在,直接创建。若存在,则是对原有文件内容的覆盖。
6.3 支持任意位置的“插入”。
11 多线程
1.理解程序、进程、线程的概念
程序可以理解为静态的代码
进程可以理解为执行中的程序。
线程可以理解为进程的进一步细分,程序的一条执行路径2.如何创建java程序的线程(重点)
方式一:继承于Thread类
class PrintNum extends Thread{
public void run(){
//子线程执行的代码
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public PrintNum(String name){
super(name);
}
}
public class TestThread {
public static void main(String[] args) {
PrintNum p1 = new PrintNum("线程1");
PrintNum p2 = new PrintNum("线程2");
p1.setPriority(Thread.MAX_PRIORITY);//10
p2.setPriority(Thread.MIN_PRIORITY);//1
p1.start();
p2.start();
}
}
方式二:实现Runnable接口
class SubThread implements Runnable{
public void run(){
//子线程执行的代码
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class TestThread{
public static void main(String[] args){
SubThread s = new SubThread();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
两种方式的对比:联系:class Thread implements Runnable
比较哪个好?实现的方式较好。①解决了单继承的局限性。②如果多个线程有共享数据的话,建议使用实现方式,同时,共享
数据所在的类可以作为Runnable接口的实现类。
线程里的常用方法:start() run() currentThread() getName() setName(String name) yield() join() sleep() isAlive()
getPriority() setPriority(int i); wait() notify() notifyAll()3.线程的生命周期
4.线程的同步机制(重点、难点)
前提:如果我们创建的多个线程,存在着共享数据,那么就有可能出现线程的安全问题:当其中一个线程操作共享数据时,还未操作完成,
另外的线程就参与进来,导致对共享数据的操作出现问题。
解决方式:要求一个线程操作共享数据时,只有当其完成操作完成共享数据,其它线程才有机会执行共享数据。
方式一:同步代码块:
synchronized(同步监视器){
//操作共享数据的代码
}
注:1.同步监视器:俗称锁,任何一个类的对象都可以才充当锁。要想保证线程的安全,必须要求所有的线程共用同一把锁!
2.使用实现Runnable接口的方式创建多线程的话,同步代码块中的锁,可以考虑是this。如果使用继承Thread类的方式,慎用this!
3.共享数据:多个线程需要共同操作的变量。 明确哪部分是操作共享数据的代码。方式二:同步方法:将操作共享数据的方法声明为synchronized。
比如:public synchronized void show(){ //操作共享数据的代码}
注:1.对于非静态的方法而言,使用同步的话,默认锁为:this。如果使用在继承的方式实现多线程的话,慎用!
2.对于静态的方法,如果使用同步,默认的锁为:当前类本身。以单例的懒汉式为例。 Class clazz = Singleton.class
总结:释放锁:wait();
不释放锁: sleep() yield() suspend() (过时,可能导致死锁)死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
死锁是我们在使用同步时,需要避免的问题!
5.线程的通信:如下的三个方法必须使用在同步代码块或同步方法中!
wait():当在同步中,执行到此方法,则此线程“等待”,直至其他线程执行notify()的方法,将其唤醒,唤醒后继续其wait()后的代码
notify()/notifyAll():在同步中,执行到此方法,则唤醒其他的某一个或所有的被wait的线程。
>例题:1.两个线程交替打印1-100自然数 2.生产者、消费者的例子
12 常用类
1. String类:不可变的字符序列(如:String str = "atguigu"; str += "javaEE")
1.关注于String常用的方法!
2.String类与基本数据类型、包装类;与字符数组、字节数组;
* 1.字符串 与基本数据类型、包装类之间转换
* ①字符串 --->基本数据类型、包装类:调用相应的包装类的parseXxx(String str);
* ①基本数据类型、包装类--->字符串:调用字符串的重载的valueOf()方法
*
* 2.字符串与字节数组间的转换
* ①字符串---->字节数组:调用字符串的getBytes()
* ②字节数组---->字符串:调用字符串的构造器
*
* 3.字符串与字符数组间的转换
* ①字符串---->字符数组:调用字符串的toCharArray();
* ②字符数组---->字符串:调用字符串的构造器
4.String与StringBuffer的转换
①String --->StringBuffer:使用StringBuffer的构造器:new StringBuffer(String str);
②StringBuffer----->String:使用StringBuffer的toString()方法
StringBuffer类:可变的字符序列
StringBuilder类:可变的字符序列,jdk5.0新加入的,效率更高,线程不安全。
常用的方法:添加:append(...) 删除 delete(int startIndex, int endIndex) 修改:setCharAt(int n ,char ch) 查询:charAt(int index)
插入:insert(int index, String str) 反转reverse() 长度:length()注:String类的不可变性:
2.时间、日期类:
2.1System类 currentTimeMillis():返回当前时间的long型值。此long值是从1970年1月1日0点0分00秒开始到当前的毫秒数。
此方法常用来计算时间差。
2.2 Date类:java.util.Date
1. Date d = new Date();//返回当前时间的Date:Mon May 12 15:17:01 CST 2014
Date d1 = new Date(15231512541241L);//返回形参处此long型值对应的日期
//getTime():返回当前日期对应的long型值。 toString()
2.3SimpleDateFormat:java.text.SimpleDateFormat
格式化 :日期--->文本 使用SimpleDateFormat的format()方法
解析:文本--->日期 使用SimpleDateFormat的parse()方法
//1.格式化1
SimpleDateFormat sdf = new SimpleDateFormat();
String date = sdf.format(new Date());
System.out.println(date);//14-5-12 下午3:24
//2.格式化2
SimpleDateFormat sdf1 = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
date = sdf1.format(new Date());
System.out.println(date);//星期一, 12 五月 2014 15:29:16 +0800
//3.解析:
Date date1 = sdf.parse("14-5-12 下午3:24");
System.out.println(date1);
date1 = sdf1.parse("星期一, 12 五月 2014 15:29:16 +0800");
// date1 = sdf1.parse("14-5-12 下午3:24");
System.out.println(date1);
2.4 Calendar:日历类
2.4.1获取实例:Calendar c = Calendar.getInstance();
2.4.2 get()/set()/add()/date getTime()/setTime()3.Math类
4.BigInteger BigDecimal类
13 反射机制
1.如何创建Class的实例(重点)
1.1过程:源文件经过编译(javac.exe)以后,得到一个或多个.class文件。.class文件经过运行(java.exe)这步,
就需要进行类的加载(通过JVM的类的加载器),记载到内存中的缓存。每一个放入缓存中的.class文件就是一个Class的实例!
1.2 Class的一个对象,对应着一个运行时类。相当于一个运行时类本身充当了Class的一个实例。
1.3 java.lang.Class是反射的源头。 接下来涉及到反射的类都在java.lang.reflect子包下。如:Field Method Constructor Type Package..
当通过Class的实例调用getMethods() --->Method , getConstructors() ---->Constructor
1.4实例化Class的方法(三种):
// 1.调用运行时类的.class属性
Class clazz1 = Person.class;
System.out.println(clazz1);Class clazz2 = Creator.class;
System.out.println(clazz2);
// 2.通过运行时类的对象,调用其getClass()方法
Person p = new Person();
Class clazz3 = p.getClass();
System.out.println(clazz3);
// 3.调用Class的静态方法forName(String className)。此方法报ClassNotFoundException
String className = "com.atguigu.java.Person";
Class clazz4 = Class.forName(className);
System.out.println(clazz4);2.有了Class实例以后,可以做什么?应用一:可以创建对应的运行时类的对象(重点)
//获取运行时类的对象:方法一
@Test
public void test1() throws Exception{
Class clazz = Class.forName("com.atguigu.review.Animal");
Object obj = clazz.newInstance();
Animal a = (Animal)obj;
System.out.println(a);
}
//调用指定的构造器创建运行时类的对象
@Test
public void test2() throws Exception{
Class clazz = Animal.class;
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Animal a = (Animal)cons.newInstance("Tom",10);
System.out.println(a);
}3.有了Class实例以后,可以做什么?应用二:获取对应的运行时类的完整的类的结构:属性、方法、构造器、包、父类、接口、泛型、注解、异常、内部类。。。
如:Method[] m1 = clazz.getMethods() :获取到对应的运行时类中声明的权限为public的方法(包含其父类中的声明的public)
Method[] m2 = clazz.getDeclaredMethods():获取到对应的运行时类中声明的所有的方法(①任何权限修饰符修饰的都能获取②不含父类中的)4.有了Class实例以后,可以做什么?应用三:调用对应的运行时类中指定的结构(某个指定的属性、方法、构造器)(重点)
//调用指定属性
@Test
public void test3() throws Exception{
Class clazz = Class.forName("com.atguigu.review.Animal");
Object obj = clazz.newInstance();
Animal a = (Animal)obj;
//调用非public的属性
Field f1 = clazz.getDeclaredField("name");
f1.setAccessible(true);
f1.set(a, "Jerry");
//调用public的属性
Field f2 = clazz.getField("age");
f2.set(a, 9);
System.out.println(f2.get(a));
System.out.println(a);
//调用static的属性
Field f3 = clazz.getDeclaredField("desc");
System.out.println(f3.get(null));
}//调用指定的方法
@Test
public void test4() throws Exception{
Class clazz = Class.forName("com.atguigu.review.Animal");
Object obj = clazz.newInstance();
Animal a = (Animal)obj;
//调用非public的方法
Method m1 = clazz.getDeclaredMethod("getAge");
m1.setAccessible(true);
int age = (Integer)m1.invoke(a);
System.out.println(age);
//调用public的方法
Method m2 = clazz.getMethod("show", String.class);
Object returnVal = m2.invoke(a,"金毛");
System.out.println(returnVal);
//调用static的方法
Method m3 = clazz.getDeclaredMethod("info");
m3.setAccessible(true);
// m3.invoke(Animal.class);
m3.invoke(null);
}5.动态代理---反射的应用。体会反射的动态性
代理设计模式的原理:
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时
将方法调用转到原始对象上静态代理:要求被代理类和代理类同时实现相应的一套接口;通过代理类的对象调用重写接口的方法时,实际上执行的是被代理类的同样的
方法的调用。动态代理:在程序运行时,根据被代理类及其实现的接口,动态的创建一个代理类。当调用代理类的实现的抽象方法时,就发起对被代理类同样
方法的调用。
涉及到的技术点:①提供一个实现了InvocationHandler接口实现类,并重写其invoke()方法
②Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),h);
//注:obj:被代理类对象 ; h:实现了InvocationHandler接口的实现类的对象例子见:day19-com.atguigu.java1.TestProxy.java例子
动态代理与AOP
14 网络编程
1.要想实现网络传输,需要考虑的问题有哪些?
1.1 如何才能准确的定位网络上的一台主机?
1.2 如何才能进行可靠的、高效的数据传输?
2.java如何实现的网络通信
2.1使用IP地址---定位一台主机 使用端口号---定位一个应用 ===>InetAddress类>如何创建一个InetAddress的对象?getByName(""); 比如:InetAddress inet = InetAddress.getByName("192.168.10.165");
>如何获取本机的一个InetAddress的对象?getLocalHost()
>域名:getHostName() ip:getHostAddress()
2.2对应有协议
对于传输层而言:分为TCP UDP (了解)
TCP的编程: Socket ServerSocket
例子:
1.客户端发送内容给服务端,服务端将内容打印到控制台上。2.客户端发送内容给服务端,服务端给予反馈。
3.从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。并关闭相应的连接。
UDP的编程: DatagramSocket DatagramPacket
URL的编程:统一资源定位符一个URL的对象,对应着互联网上一个资源。
//我们可以通过URL的对象调用其相应的方法,将此资源读取(“下载”)