JAVA的一些小笔记(长篇警告) 1.一个类中定义了多个构造器,彼此会构成重载。
2.一个类中至少有一个构造器,如果没有自己定义构造器,系统会有一个默认构造器。
多态的本质 多态实际上就是父类的引用指向子类的对象,实际上就是子类重写了父类的方法。
1 2 3 4 5 Person p2 = new Man(); Man p3=(Man)p2;
instanceof 操作符(属于) 1 2 3 4 5 6 if (a instanceof b){ .... } if (a instanceof object){ ... }
大概意思就是 a 是否为类b的实例,如果true,则可有(b)a,a可以被强转为b。
final 语句 ①当final语句修饰变量时,该变量即视为常量。
②当final修饰方法时,该方法不能被子类重写。
③当final修饰类时,该类是最终的,不能被继承。
接口的理解 接口本质是一种规范,一种限制。接口解决了多继承的问题。
一个接口可以继承多个接口
1 2 3 4 5 6 7 8 9 interface a { ... } interface b { ... } interface c extends a , b { ... }
一个类可以实现多个接口
1 2 3 class d implements a , b { .... }
jdk8以后的方法
接口中的默认方法 在接口中用default
关键字定义接口的默认方法。普通接口方法是不能有实现的,默认方法必须有实现:
1 2 3 4 5 6 7 8 public interface MyInterface { default void defaultMethod () { } }
为什么需要默认方法 在Java8之前,接口只能有抽象方法。如果不强制所有实现类创建新方法的实现,就不能向现有接口添加新功能。
Java8新增默认方法的原因非常明显。
在一个典型的基于抽象的设计中,一个接口有一个或多个实现类。接口要新增方法,所有的实现都要新增这个方法的实现。否则就不满足接口的约束。
默认接口方法是处理此问题的解决方案。在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。
默认方法的使用 定义MobilePhone接口,其中setTime,getLengthInCm为默认方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 interface MobilePhone { String getBrand () ; String getColor () ; Double getLength () ; default String setTime (String newTime) { return "time set to " + newTime; } default String getLengthInCm () { return getLength() / 10 + "cm" ; } }
默认方法在实现类中可以直接使用 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class DefaultTests implements MobilePhone { @Override public String getBrand () { return "iphone" ; } @Override public String getColor () { return "red" ; } @Override public Double getLength () { return 150.00 ; } @Test public void defaultTest () { System.out.println(setTime("8:00 am" )); System.out.println(getLengthInCm()); } }
结果:
1 2 time set to 8:00 am 15.0 cm
如果在某个时候我们往接口添加更多的默认方法,实现类可以不用修改继续使用 。
默认方法的最典型用法是逐步为接口提供附加功能,而不破坏实现类。
此外,它们还可以用来为现有的抽象方法提供额外的功能 :
1 2 3 4 5 6 7 8 9 10 11 12 13 interface MobilePhone { Double getLength () ; default String getLengthInCm () { return getLength() / 10 + "cm" ; } }
默认方法的多继承 Apple接口和Samsung接口继承MobilePhone接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 interface Apple extends MobilePhone { @Override default String setTime (String newTime) { return "time set to " + newTime + " in apple" ; } } interface Samsung extends MobilePhone { @Override default String setTime (String newTime) { return "time set to " + newTime + " in samsung" ; } }
DefaultTests实现Apple和Samsung接口,必须对setTime
方法进行重写,否则对象将不知道该使用Apple的setTime方法还是Samsung的setTime方法,因为它们同名了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class DefaultTests implements Apple , Samsung { @Override public String getBrand () { return "iphone" ; } @Override public String getColor () { return "red" ; } @Override public Double getLength () { return 150.00 ; } @Override public String setTime (String newTime) { return Apple.super .setTime(newTime); } @Test public void defaultTest () { System.out.println(setTime("8:00 am" )); System.out.println(getLengthInCm()); } }
结果
1 2 time set to 8:00 am in apple 15.0 cm
总结 在本文中,我们深入探讨了Java8中接口默认方法的使用。乍一看,这个特性可能有点马虎,特别是纯粹从面向对象的角度来看。理想情况下,接口不应该封装行为,而应该只用于定义特定类型的公共API。
但是在维护现有代码的向后兼容性时,静态方法 和默认方法是一种很好的折衷。
@Override 这个关键字可加可不加,注意是提醒系统,下面要进行的是子类重写(如果下面方法没有在父类中出现,则会报错)。这样就不会出现记错父类方法名(你以为你重写了,但实际上是新建了一个子类方法)的情况。(原来这个叫注解)
equals和==的区别 Object中的equals较的是地址值。也就是说,同一个类定义两个相同的对象(各种属性相同),然而equals却为0,因为地址不一样。(string类型的equals被重写过)
static修饰符 ①修饰变量:修饰类中的变量,使得各种实例化对象共用。
②修饰方法:
静态方法可以直接使用类名去调用。不需要创建一个对象。(单例模式可以用)
总结 :
static修饰代码段 静态代码块随着类的加载而执行,而且只执行一次,而且比main函数的执行要快。比如现在x = new A(); 其实是先加载了A这个类,再把x赋予了A的实例。下面有个很好的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class StaticDemo {static {System.out.println("父类静态代码块被执行" ); } void show () {System.out.println("父类方法被执行" ); } } public class StaticTest extends StaticDemo {static {System.out.println("子类静态代码块被执行" ); } void show () {System.out.println("子类方法被执行" ); } public static void main (String[] hq) {System.out.println("main函数" ); StaticTest staticTest = new StaticTest(); } }
打印结果
单例模式 意思就是创造一个类,那个类只能衍生出一个实例,其中有几个要点。
饿汉式
这里获得bank对象的方法是static的,可以在不创建类的实例对象的情况下,使用该方法。
懒汉式
为什么一个叫懒一个叫饿呢,是因为懒是需要用的时候才造,饿是先造好了,一直饿着不用
main函数的讲解 静态方法中不能调用非静态的东西!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class maintest { public static void main (String[] args) { show(); show2(); maintest x = new maintest(); x.show(); } void show () { ....... } static void show2 () { ..... } }
匿名对象、匿名内部类、匿名实现某一种接口 匿名对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Person { public String name; public int age; public Person (String name, int age) { this .name = name; this .age = age; } public void tell () { System.out.println("姓名:" + name + ",年龄:" + age); } public static void main (String[] args) { new Person("张三" , 30 ).tell(); } }
匿名子类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Test15 { public static void main (String[] args) { Test015 one = new Test015(){ @Override public void test1 () { System.out.println("333333333333" ); } }; Test015 tow = new Test015(){ @Override public void test1 () { super .test1(); System.out.println("333333333333" ); } }; one.test1(); tow.test1(); } } class Test015 { public void test1 () { System.out.println("111111111111" ); } }
内部类 注意static一般不能修饰类,但是可以修饰一个类中的内部类。
基本上关注最后的三个问题就OK了
注意,如果外部类和内部类有个属性重名了,则不能直接使用name,这样来访问属性,得说清楚。
lambda表达式
一些例子
语法精简 能用Lambda实现的接口,都是函数式接口,就是接口中只有一个抽象方法,lambda函数重写的也是那个方法。
方法引用 感觉就是拿::当.用
稍稍有点不一样的是,构造器的
异常 try-catch-finally 不再赘述
throws是把异常抛给执行者,一般是执行者负责处理异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class OverrideTest { public static void main (String[] args) { OverrideTest test = new OverrideTest(); test.display(new SubClass()); } public void display (SuperClass s) { try { s.method(); } catch (IOException e) { e.printStackTrace(); } } } class SuperClass { public void method () throws IOException { } } class SubClass extends SuperClass { public void method () throws FileNotFoundException { } }
程序、进程、线程的概念
多线程第一招:继承自Thread 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.fancyrufus.threadtest;class MyThread extends Thread { @Override public void run () { super .run(); for (int i=0 ;i<100 ;i++) System.out.println(i); } } public class MyThreadtest { public static void main (String[] args) { MyThread th1 = new MyThread(); MyThread th2 = new MyThread(); th1.start(); th2.start(); } }
需要注意的点
对于同一个创建好的对象,不能.start()之后再次.start()。
Thread类的一些常用方法
又一种总结(简洁版)
线程调度
多线程创建第二招(实现Runnable接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyThread implements Runnable { @Override public void run () { for (int i=0 ;i<100 ;i++) System.out.println(Thread.currentThread().getName()+": " +i); } } public class MyThreadtest { public static void main (String[] args) { MyThread mth = new MyThread(); Thread th1 = new Thread(mth); Thread th2 = new Thread(mth); th1.setName("老八" ); th2.setName("老六" ); th1.start(); th2.start(); } }
线程共用参数的问题 当使用继承自Thread来进行多线程操作 的时候,此时将参数定义在Thread的子类中,并以private和static进行修饰。
1 2 3 4 class window extends Thread { private static int ticket = 100 ; .... }
当实现Runnable接口来进行多线程操作 的时候,此时将参数定义在实现接口的类中,后面创建多线程的时候,统一用同一个Runnable实现类的实例置入Thread构造器参数
1 2 3 4 5 6 7 8 9 10 11 12 class window implements Runnable { private int ticket = 100 ; } public class MyThreadtest { public static void main (String[] args) { MyThread mth = new MyThread(); Thread th1 = new Thread(mth); Thread th2 = new Thread(mth); Thread th3 = new Thread(mth); .... } }
但是注意,这里还没有考虑线程的安全问题。
线程的生命周期
线程的安全问题 当多个线程共享数据时,就会出现线程的安全问题。
以车票为例,洞悉线程的安全问题
JAVA中的解决方式:同步方法
就是把需要监视的代码块给框起来,监视器随便找一个对象就可。(甚至可以直接拿一个obj实例化的对象来)注意多个线程需要共用一把锁,也就是说,这个锁需要让每个线程都能访问。比如要实例化一个对象,得让所有线程都能访问这个对象,否则,如果是每个线程一个这个对象的话,就无法实现线程安全。
使用Runnable接口的安全示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Window1 implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ){ synchronized (this ){ if (ticket > 0 ) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket); ticket--; } else { break ; } } } } } public class WindowTest1 { public static void main (String[] args) { Window1 w = new Window1(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口1" ); t2.setName("窗口2" ); t3.setName("窗口3" ); t1.start(); t2.start(); t3.start(); } }
继承自Thread的安全示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Window2 extends Thread { private static int ticket = 100 ; private static Object obj = new Object(); @Override public void run () { while (true ){ synchronized (Window2.class){ if (ticket > 0 ){ try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":卖票,票号为:" + ticket); ticket--; }else { break ; } } } } } public class WindowTest2 { public static void main (String[] args) { Window2 t1 = new Window2(); Window2 t2 = new Window2(); Window2 t3 = new Window2(); t1.setName("窗口1" ); t2.setName("窗口2" ); t3.setName("窗口3" ); t1.start(); t2.start(); t3.start(); } }
同步监视的方式,解决了线程的安全问题,但是也有一些局限性,比如在执行这个被监视的过程时间中,只能有一个线程工作。这样会导致效率降低。
当使用runnable实现多线程的时候,在synchronized( )中使用this关键字,简单又方便
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Window1 implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ){ synchronized (this ){ if (ticket > 0 ) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket); ticket--; } else { break ; } } } } } public class WindowTest1 { public static void main (String[] args) { Window1 w = new Window1(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口1" ); t2.setName("窗口2" ); t3.setName("窗口3" ); t1.start(); t2.start(); t3.start(); } }
解决方式二:同步方法
使用Runnable接口实现 时,直接把待同步的方法前面加上synchronized关键字,效果等效于把这个方法代码块框住,并在synchronized里面填上this监视器。注意,之前说过this的操作只能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Window3 implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ) { show(); } } private synchronized void show () { if (ticket > 0 ) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket); ticket--; } } }
使用Thread类继承实现 时,待同步的方法还得加上static关键字,此时相当于synchronized关键字里面放上当前类(不是当前类的实例化对象!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Window4 extends Thread { private static int ticket = 100 ; @Override public void run () { while (true ) { show(); } } private static synchronized void show () { if (ticket > 0 ) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket); ticket--; } } }
改写懒汉式的线程安全版本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Bank { private Bank () {} private static Bank instance = null ; public static Bank getInstance () { if (instance == null ){ synchronized (Bank.class) { if (instance == null ){ instance = new Bank(); } } } return instance; } }
线程死锁 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class ThreadTest { public static void main (String[] args) { StringBuffer s1 = new StringBuffer(); StringBuffer s2 = new StringBuffer(); new Thread(){ @Override public void run () { synchronized (s1){ s1.append("a" ); s2.append("1" ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.append("b" ); s2.append("2" ); System.out.println(s1); System.out.println(s2); } } } }.start(); new Thread(new Runnable() { @Override public void run () { synchronized (s2){ s1.append("c" ); s2.append("3" ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.append("d" ); s2.append("4" ); System.out.println(s1); System.out.println(s2); } } } }).start(); } }
使用lock锁也可以解决线程安全问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Window implements Runnable { private int ticket = 100 ; private ReentrantLock lock = new ReentrantLock(); @Override public void run () { while (true ){ try { lock.lock(); if (ticket > 0 ){ try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket); ticket--; }else { break ; } }finally { lock.unlock(); } } } }
注意如果使用继承自Thread类时,想要使用lock锁,需要将🔒定义成静态的。
线程通信 关键是notify();能够释放优先级最高的线程,以及在wait的时候,线程进入阻塞状态,锁会被自动释放
线程通信的例子:使用两个线程打印 1-100。线程1, 线程2 交替打印
涉及到的三个方法:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
说明:
1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。
否则,会出现IllegalMonitorStateException异常
3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。
面试题:sleep() 和 wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()
2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Number implements Runnable { private int number = 1 ; private Object obj = new Object(); @Override public void run () { while (true ){ synchronized (obj) { obj.notify(); if (number <= 100 ){ try { Thread.sleep(10 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + number); number++; try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { break ; } } } } } public class CommunicationTest { public static void main (String[] args) { Number number = new Number(); Thread t1 = new Thread(number); Thread t2 = new Thread(number); t1.setName("线程1" ); t2.setName("线程2" ); t1.start(); t2.start(); } }
船新线程创建方式 实现callable接口
需要使用futuretask类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class NumThread implements Callable { @Override public Object call () throws Exception { int sum = 0 ; for (int i = 1 ; i <= 100 ; i++) { if (i % 2 == 0 ){ System.out.println(i); sum += i; } } return sum; } } public class ThreadNew { public static void main (String[] args) { NumThread numThread = new NumThread(); FutureTask futureTask = new FutureTask(numThread); new Thread(futureTask).start(); try { Object sum = futureTask.get(); System.out.println("总和为:" + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
使用线程池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class NumberThread implements Runnable { @Override public void run () { for (int i = 0 ;i <= 100 ;i++){ if (i % 2 == 0 ){ System.out.println(Thread.currentThread().getName() + ": " + i); } } } } class NumberThread1 implements Runnable { @Override public void run () { for (int i = 0 ;i <= 100 ;i++){ if (i % 2 != 0 ){ System.out.println(Thread.currentThread().getName() + ": " + i); } } } } public class ThreadPool { public static void main (String[] args) { ExecutorService service = Executors.newFixedThreadPool(10 ); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; service.execute(new NumberThread()); service.execute(new NumberThread1()); service.shutdown(); } }
生产者消费者经典问题(线程各种操作融合) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 class Clerk { private int productCount = 0 ; public synchronized void produceProduct () { if (productCount < 20 ){ productCount++; System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品" ); notify(); }else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void consumeProduct () { if (productCount > 0 ){ System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品" ); productCount--; notify(); }else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Producer extends Thread { private Clerk clerk; public Producer (Clerk clerk) { this .clerk = clerk; } @Override public void run () { System.out.println(getName() + ":开始生产产品....." ); while (true ){ try { Thread.sleep(10 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } class Consumer extends Thread { private Clerk clerk; public Consumer (Clerk clerk) { this .clerk = clerk; } @Override public void run () { System.out.println(getName() + ":开始消费产品....." ); while (true ){ try { Thread.sleep(20 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); } } } public class ProductTest { public static void main (String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); p1.setName("生产者1" ); Consumer c1 = new Consumer(clerk); c1.setName("消费者1" ); Consumer c2 = new Consumer(clerk); c2.setName("消费者2" ); p1.start(); c1.start(); c2.start(); } }
数组和集合和Map
注意这里的map,一个key不可以对应多个value,和生活中的函数差不多。
集合中的contain方法、以及集合和数组之间的转化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 package com.atguigu.java;import org.junit.Test;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.List;public class CollectionTest { @Test public void test1 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); boolean contains = coll.contains(123 ); System.out.println(contains); System.out.println(coll.contains(new String("Tom" ))); System.out.println(coll.contains(new Person("Jerry" ,20 ))); Collection coll1 = Arrays.asList(123 ,4567 ); System.out.println(coll.containsAll(coll1)); } @Test public void test2 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); coll.remove(1234 ); System.out.println(coll); coll.remove(new Person("Jerry" ,20 )); System.out.println(coll); Collection coll1 = Arrays.asList(123 ,456 ); coll.removeAll(coll1); System.out.println(coll); } @Test public void test3 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); Collection coll1 = new ArrayList(); coll1.add(456 ); coll1.add(123 ); coll1.add(new Person("Jerry" ,20 )); coll1.add(new String("Tom" )); coll1.add(false ); System.out.println(coll.equals(coll1)); } @Test public void test4 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); System.out.println(coll.hashCode()); Object[] arr = coll.toArray(); for (int i = 0 ;i < arr.length;i++){ System.out.println(arr[i]); } List<String> list = Arrays.asList(new String[]{"AA" , "BB" , "CC" }); System.out.println(list); List arr1 = Arrays.asList(new int []{123 , 456 }); System.out.println(arr1.size()); List arr2 = Arrays.asList(new Integer[]{123 , 456 }); System.out.println(arr2.size()); } }
list接口常用方法
遍历list
集合中元素的添加方法 太庙了
注解 注解有几种种类
自定义注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
后面暂时跳过,过于阴间和无聊。
迭代器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package com.atguigu.java;import org.junit.Test;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;public class IteratorTest { @Test public void test1 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); Iterator iterator = coll.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } @Test public void test2 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); while (coll.iterator().hasNext()){ System.out.println(coll.iterator().next()); } } @Test public void test3 () { Collection coll = new ArrayList(); coll.add(123 ); coll.add(456 ); coll.add(new Person("Jerry" ,20 )); coll.add(new String("Tom" )); coll.add(false ); Iterator iterator = coll.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); if ("Tom" .equals(obj)){ iterator.remove(); } } iterator = coll.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
泛型初始理解 泛型解决的问题,可以就在编译时判断类型是否错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class GenericTest { @Test public void test1 () { ArrayList list = new ArrayList(); list.add(78 ); list.add(76 ); list.add(89 ); list.add(88 ); for (Object score : list){ int stuScore = (Integer) score; System.out.println(stuScore); } }
这里如果在实现的接口后加上泛型,那么也是在声明的时候,声明了一个泛型类。这里声明类的时候,加的泛型标志<>里面的东西只是一个类似占位符的东西,等把类实例化时加上的<>里面的类名等于替换了原来定义时里面所有的占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class Employee implements Comparable <Employee > { private String name; private int age; private MyDate birthday; public Employee (String name, int age, MyDate birthday) { this .name = name; this .age = age; this .birthday = birthday; } @Override public String toString () { return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}' ; } @Override public int compareTo (Employee o) { return this .name.compareTo(o.name); } }
注意泛型什么时候能用,什么时候不能用
1 2 3 PersonNum<Integer> man1 = 123 ;
泛型还有很多讲究,以及一些细节问题
泛型Pro
注意,还有几点,泛型的<>中只能放类或者包装类,能放Integer却不能放int,因为int是基本数据类型。
考虑继承时,泛型的关系。
o注意,还有几点,泛型的<>中只能放类hu,考虑继承时,泛型的关系。
泛型方法
泛型方法和其所属的类是不是泛型类都没有什么关系。注意声明时的格式。在返回值类型前面,有对泛型的一个特殊声明。
两个加入了不同限定之后的泛型,是不具备子父类关系的
通配符
这里的<?>就像是一个不同泛型下的父类了,记住,原来这种不是的子类,无法将前者的对象付给后者的引用
使用小场景
对于List<?>只能读不能写.
异常补习
一些示例
自定义异常
IO操作 file常用方法
这个方法等效于剪切+改名。
是否是文件,注意如果原本磁盘中不存在那个文件,你new一个,那那个文件也是不存在的。
file类的另一些操作。
各种各样的IO类
字符输入流
对于异常处理,请勿使用throw,否者可能导致流无法关闭
使用read的重载方法,可以一次性读入多个字符到数组中
字符输出流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Test public void testFileWriter () { FileWriter fw = null ; try { File file = new File("hello1.txt" ); fw = new FileWriter(file,false ); fw.write("I have a dream!\n" ); fw.write("you need to have a dream!" ); } catch (IOException e) { e.printStackTrace(); } finally { if (fw != null ){ try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }
注意这里也不能用原来throw的方式,否则就会终止程序。
实现文件的复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Test public void testFileReaderFileWriter () { FileReader fr = null ; FileWriter fw = null ; try { File srcFile = new File("hello.txt" ); File destFile = new File("hello2.txt" ); fr = new FileReader(srcFile); fw = new FileWriter(destFile); char [] cbuf = new char [5 ]; int len; while ((len = fr.read(cbuf)) != -1 ){ fw.write(cbuf,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw != null ) fw.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fr != null ) fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
注意,上面是字符流的操作,只能处理字符型文件,如果想实现图片那些的复制,出来的结果将会是不正确的。
字节流读入写出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public class FileInputOutputStreamTest { @Test public void testFileInputStream () { FileInputStream fis = null ; try { File file = new File("hello.txt" ); fis = new FileInputStream(file); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer)) != -1 ){ String str = new String(buffer,0 ,len); System.out.print(str); } } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void testFileInputOutputStream () { FileInputStream fis = null ; FileOutputStream fos = null ; try { File srcFile = new File("爱情与友情.jpg" ); File destFile = new File("爱情与友情2.jpg" ); fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer)) != -1 ){ fos.write(buffer,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null ){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
测试总结
缓冲流
小总结
转换流
转换流在处理文件时,有两个参数,一个是待转换的流对象,一个是转换时的编码格式。比如对于一个UTF-8的文件,以UTF-8读入,以gbk写出,那就成功实现了转换操作。
对象流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 @Test public void testObjectOutputStream () { ObjectOutputStream oos = null ; try { oos = new ObjectOutputStream(new FileOutputStream("object.dat" )); oos.writeObject(new String("我爱北京天安门" )); oos.flush(); oos.writeObject(new Person("王铭" ,23 )); oos.flush(); oos.writeObject(new Person("张学良" ,23 ,1001 ,new Account(5000 ))); oos.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null ){ try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void testObjectInputStream () { ObjectInputStream ois = null ; try { ois = new ObjectInputStream(new FileInputStream("object.dat" )); Object obj = ois.readObject(); String str = (String) obj; Person p = (Person) ois.readObject(); Person p1 = (Person) ois.readObject(); System.out.println(str); System.out.println(p); System.out.println(p1); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (ois != null ){ try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
自定义类实现可序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 public class Person implements Serializable { public static final long serialVersionUID = 475463534532L ; private String name; private int age; private int id; private Account acct; public Person (String name, int age, int id) { this .name = name; this .age = age; this .id = id; } public Person (String name, int age, int id, Account acct) { this .name = name; this .age = age; this .id = id; this .acct = acct; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + ", acct=" + acct + '}' ; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public Person (String name, int age) { this .name = name; this .age = age; } public Person () { } } class Account implements Serializable { public static final long serialVersionUID = 4754534532L ; private double balance; @Override public String toString () { return "Account{" + "balance=" + balance + '}' ; } public double getBalance () { return balance; } public void setBalance (double balance) { this .balance = balance; } public Account (double balance) { this .balance = balance; } }
NIO 概述
Paths可以用于返回创建好的Path对象。
突然补习 如果是main方法里的路径,则默认是从当前工程下开始的。如果是单元测试时的路径,则是当前module下的。
网络编程 InetAddress类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package com.atguigu.java1;import java.net.InetAddress;import java.net.UnknownHostException;public class InetAddressTest { public static void main (String[] args) { try { InetAddress inet1 = InetAddress.getByName("192.168.10.14" ); System.out.println(inet1); InetAddress inet2 = InetAddress.getByName("www.atguigu.com" ); System.out.println(inet2); InetAddress inet3 = InetAddress.getByName("127.0.0.1" ); System.out.println(inet3); InetAddress inet4 = InetAddress.getLocalHost(); System.out.println(inet4); System.out.println(inet2.getHostName()); System.out.println(inet2.getHostAddress()); } catch (UnknownHostException e) { e.printStackTrace(); } } }
Socket的妙用 TCP网络编程例题1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 package com.fancyrufus.Intest;import org.junit.Test;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class TCPTest1 { @Test public void client () { Socket socket = null ; OutputStream os = null ; try { InetAddress inet = InetAddress.getByName("localhost" ); socket = new Socket(inet,8899 ); os = socket.getOutputStream(); os.write("你好,我是客户端mm" .getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (os != null ){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null ){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void server () { ServerSocket ss = null ; Socket socket = null ; InputStream is = null ; ByteArrayOutputStream baos = null ; try { ss = new ServerSocket(8899 ); socket = ss.accept(); is = socket.getInputStream(); baos = new ByteArrayOutputStream(); byte [] buffer = new byte [5 ]; int len; while ((len = is.read(buffer)) != -1 ){ baos.write(buffer,0 ,len); } System.out.println(baos.toString()); System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据" ); } catch (IOException e) { e.printStackTrace(); } finally { if (baos != null ){ try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null ){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null ){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (ss != null ){ try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
TCP网络编程例题2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package com.atguigu.java1;import org.junit.Test;import java.io.*;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class TCPTest2 { @Test public void client () throws IOException { Socket socket = new Socket(InetAddress.getByName("127.0.0.1" ),9090 ); OutputStream os = socket.getOutputStream(); FileInputStream fis = new FileInputStream(new File("beauty.jpg" )); byte [] buffer = new byte [1024 ]; int len; while ((len = fis.read(buffer)) != -1 ){ os.write(buffer,0 ,len); } fis.close(); os.close(); socket.close(); } @Test public void server () throws IOException { ServerSocket ss = new ServerSocket(9090 ); Socket socket = ss.accept(); InputStream is = socket.getInputStream(); FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg" )); byte [] buffer = new byte [1024 ]; int len; while ((len = is.read(buffer)) != -1 ){ fos.write(buffer,0 ,len); } fos.close(); is.close(); socket.close(); ss.close(); } }
TCP网络编程例题3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 package com.atguigu.java1;import org.junit.Test;import java.io.*;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class TCPTest3 { @Test public void client () throws IOException { Socket socket = new Socket(InetAddress.getByName("127.0.0.1" ),9090 ); OutputStream os = socket.getOutputStream(); FileInputStream fis = new FileInputStream(new File("beauty.jpg" )); byte [] buffer = new byte [1024 ]; int len; while ((len = fis.read(buffer)) != -1 ){ os.write(buffer,0 ,len); } socket.shutdownOutput(); InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte [] bufferr = new byte [20 ]; int len1; while ((len1 = is.read(buffer)) != -1 ){ baos.write(buffer,0 ,len1); } System.out.println(baos.toString()); fis.close(); os.close(); socket.close(); baos.close(); } @Test public void server () throws IOException { ServerSocket ss = new ServerSocket(9090 ); Socket socket = ss.accept(); InputStream is = socket.getInputStream(); FileOutputStream fos = new FileOutputStream(new File("beauty2.jpg" )); byte [] buffer = new byte [1024 ]; int len; while ((len = is.read(buffer)) != -1 ){ fos.write(buffer,0 ,len); } System.out.println("图片传输完成" ); OutputStream os = socket.getOutputStream(); os.write("你好,美女,照片我已收到,非常漂亮!" .getBytes()); fos.close(); is.close(); socket.close(); ss.close(); os.close(); } }
UDP网络编程例题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.atguigu.java1;import org.junit.Test;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;public class UDPTest { @Test public void sender () throws IOException { DatagramSocket socket = new DatagramSocket(); String str = "我是UDP方式发送的导弹" ; byte [] data = str.getBytes(); InetAddress inet = InetAddress.getLocalHost(); DatagramPacket packet = new DatagramPacket(data,0 ,data.length,inet,9090 ); socket.send(packet); socket.close(); } @Test public void receiver () throws IOException { DatagramSocket socket = new DatagramSocket(9090 ); byte [] buffer = new byte [100 ]; DatagramPacket packet = new DatagramPacket(buffer,0 ,buffer.length); socket.receive(packet); System.out.println(new String(packet.getData(),0 ,packet.getLength())); socket.close(); } }
通过先后启动接收端和发送端,就能直观的感受到UDP和TCP的区别.
URL编程
可变参数 在定义方法时,在最后一个形参后加上三点 … ,就表示该形参可以接受多个参数值,多个参数值被当成数组传入。上述定义有几个要点需要注意:
可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数
由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数
Java的可变参数,会被编译器转型为一个数组
变长参数在编译为字节码后,在方法签名中就是以数组形态出现的。这两个方法的签名是一致的,不能作为方法的重载。如果同时出现,是不能编译通过的。可变参数可以兼容数组,反之则不成立
1 2 3 4 5 6 public void foo (String...varargs) {}foo("arg1" , "arg2" , "arg3" ); foo(new String[]{"arg1" , "arg2" , "arg3" });
J2SE 1.5 中新增了**”泛型”**的机制,可以在一定条件下把一个类型参数化。例如,可以在编写一个类的时候,把一个方法的形参的类型用一个标识符(如T)来代表, 至于这个标识符到底表示什么类型,则在生成这个类的实例的时候再行指定。这一机制可以用来提供更充分的代码重用和更严格的编译时类型检查。不过泛型机制却不能和个数可变的形参配合使用。如果把一个能和不确定个实参相匹配的形参的类型,用一个标识符来代表,那么编译器会给出一个 “generic array creation” 的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Varargs { public static void test (String... args) { for (String arg : args) { System.out.println(arg); } } }
方法重载 优先匹配固定参数 调用一个被重载的方法时,如果此调用既能够和固定参数的重载方法匹配,也能够与可变长参数的重载方法匹配,则选择固定参数的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Varargs { public static void test (String... args) { System.out.println("version 1" ); } public static void test (String arg1, String arg2) { System.out.println("version 2" ); } public static void main (String[] args) { test("a" ,"b" ); test(); } }
匹配多个可变参数 调用一个被重载的方法时,如果此调用既能够和两个可变长参数的重载方法匹配,则编译出错:
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Varargs { public static void test (String... args) { System.out.println("version 1" ); } public static void test (String arg1, String... arg2) { System.out.println("version 2" ); } public static void main (String[] args) { test("a" ,"b" ); } }
反射 感觉挺难,希望能坚持下去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 public class ReflectionTest { @Test public void test1 () { Person p1 = new Person("Tom" , 12 ); p1.age = 10 ; System.out.println(p1.toString()); p1.show(); } @Test public void test2 () throws Exception { Class clazz = Person.class; Constructor cons = clazz.getConstructor(String.class,int .class); Object obj = cons.newInstance("Tom" , 12 ); Person p = (Person) obj; System.out.println(p.toString()); Field age = clazz.getDeclaredField("age" ); age.set(p,10 ); System.out.println(p.toString()); Method show = clazz.getDeclaredMethod("show" ); show.invoke(p); System.out.println("*******************************" ); Constructor cons1 = clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true ); Person p1 = (Person) cons1.newInstance("Jerry" ); System.out.println(p1); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p1,"HanMeimei" ); System.out.println(p1); Method showNation = clazz.getDeclaredMethod("showNation" , String.class); showNation.setAccessible(true ); String nation = (String) showNation.invoke(p1,"中国" ); System.out.println(nation); } @Test public void test3 () throws ClassNotFoundException { Class clazz1 = Person.class; System.out.println(clazz1); Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2); Class clazz3 = Class.forName("com.atguigu.java.Person" ); System.out.println(clazz3); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.atguigu.java.Person" ); System.out.println(clazz4); System.out.println(clazz1 == clazz4); } @Test public void test4 () { Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int [][].class; Class c5 = ElementType.class; Class c6 = Override.class; Class c7 = int .class; Class c8 = void .class; Class c9 = Class.class; int [] a = new int [10 ]; int [] b = new int [100 ]; Class c10 = a.getClass(); Class c11 = b.getClass(); System.out.println(c10 == c11); } }
代码前面的Constructor、Method那些都是import进来的东西
1 2 3 import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;
注意运行时类的定义:加载到内存中的类,我们就称为运行时类
Class类的实例就对应着一个运行时类!也就意味着,我们平常是Class c = xxx.class 而不是重新new一个Class。