定义一个线程
public class MyThread extends Thread { @Override public void run() { for (int x = 0; x < 200; x++) { System.out.println(x); } } }启动一个线程
// 面试题:run()和start()的区别? // run():仅仅是封装被线程执行的代码,直接调用是普通方法 // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
public static void main(String[] args) { // 创建两个线程对象 MyThread my1 = new MyThread(); my1.start(); }常用方法
* public final String getName():获取线程的名称。
* public final void setName(String name):设置线程的名称
* 针对不是Thread类的子类中如何获取线程对象名称呢? * public static Thread currentThread():返回当前正在执行的线程对象 * Thread.currentThread().getName()
举个栗子:获得main函数线程名称
public static void main(String[] args) { //public static Thread currentThread():返回当前正在执行的线程对象 System.out.println(Thread.currentThread().getName()); }* public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。 * 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。
* public final void join():等待该线程跑完终止。
* 如何获取线程对象的优先级? * public final int getPriority():返回线程对象的优先级 * 如何设置线程对象的优先级呢? * public final void setPriority(int newPriority):更改线程的优先级。 * * 注意: * 线程默认优先级是5。 * 线程优先级的范围是:1-10。 * 线程优先级高仅仅表示线程获取的 CPU时间片的几率高,次数多的时候看到比较明显。
* 线程休眠 * public static void sleep(long millis)
* 线程的骨折
* public final void stop():让线程停止,过时了,但是还可以使用。 * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。
*线程的分配
* public static void yield():暂停当前正在执行的线程对象,并执行其他线程。如果其他线程也暂停了 ,就执行刚开始暂停的线程,所以某种情况下回很和谐。 * 让多个线程的执行更和谐,但是不能靠它保证一人一次。
创建线程的第二种方式
public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 100; x++) { // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用 System.out.println(Thread.currentThread().getName() + ":" + x); } } }跑起来
public static void main(String[] args) { // 创建MyRunnable类的对象 MyRunnable my = new MyRunnable(); Thread t1 = new Thread(my, "林青霞"); Thread t2 = new Thread(my, "刘意"); t1.start(); t2.start(); }第二种创建线程的方式更加体现数据共享的概念,只创建了一个线程对象,可以实现某些功能比如:买票。
买票问题的解决方法
个人向:实现接口创建线程,数据共享,所以obj成员变量也是同一个。相当于三个人进同一个屋子,门上了把锁,所以保证了,tickets的值是更新后的。
public class ThreadJoin extends Thread{ private int tickets=100; private Object obj=new Object(); @Override public void run() { while (true) { synchronized(obj){ if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); } } } } }任何的东西有好必有坏。
* 同步的好处 * 同步的出现解决了多线程的安全问题。 * 同步的弊端 * 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
除了给成员变量上锁外,还有其他方法
* A:同步代码块的锁对象是谁呢? * 任意对象。 * * B:同步方法的格式及锁对象问题? * 把同步关键字加在方法上。 * * 同步方法是谁呢? * this * * C:静态方法及锁对象问题? * 静态方法的锁对象是谁呢? * 类的字节码文件对象。(反射会讲)
线程安全
StringBuffer sb = new StringBuffer(); Vector<String> v = new Vector<String>(); Hashtable<String, String> h = new Hashtable<String, String>(); // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你 // 那么到底用谁呢? // public static <T> List<T> synchronizedList(List<T> list) List<String> list1 = new ArrayList<String>();// 线程不安全 List<String> list2 = Collections.synchronizedList(new ArrayList<String>()); // 线程安全线程的生命周期
* Lock: * void lock(): 获取锁。 * void unlock():释放锁。 * ReentrantLock是Lock的实现类.
public class SellTicket implements Runnable { // 定义票 private int tickets = 100; // 定义锁对象 private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { // 加锁 lock.lock(); if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); } } finally { // 释放锁 lock.unlock(); } } } }* 同步的弊端: * A:效率低 * B:容易产生死锁 * * 死锁: * 两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
public class MyLock { // 创建两把锁对象 public static final Object objA = new Object(); public static final Object objB = new Object(); } ------------------------------------------------------- public class DieLock extends Thread { private boolean flag; public DieLock(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { synchronized (MyLock.objA) { System.out.println("if objA"); synchronized (MyLock.objB) { System.out.println("if objB"); } } } else { synchronized (MyLock.objB) { System.out.println("else objB"); synchronized (MyLock.objA) { System.out.println("else objA"); } } } } } -------------------------------------------------------------------- public static void main(String[] args) { DieLock dl1 = new DieLock(true); DieLock dl2 = new DieLock(false); dl1.start(); dl2.start(); }生产者消费者模型
* Object类中提供了三个方法: * wait():等待 * notify():唤醒单个线程 * notifyAll():唤醒所有线程 * 为什么这些方法不定义在Thread类中呢? * 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。 * 所以,这些方法必须定义在Object类中。
public class Student { String name; int age; boolean flag; // 默认情况是没有数据,如果是true,说明有数据 } -------------------------------------------------------- public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { //判断有没有 if(s.flag){ try { s.wait(); //t1等着,释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } if (x % 2 == 0) { s.name = "林青霞"; s.age = 27; } else { s.name = "李二狗"; s.age = 30; } x++; //x=1 //修改标记 s.flag = true; //唤醒线程 s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。 } //t1有,或者t2有 } } } ------------------------------------------------------------------------------ public class GetThread implements Runnable { private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { if(!s.flag){ try { s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(s.name + "---" + s.age); //林青霞---27 //刘意---30 //修改标记 s.flag = false; //唤醒线程 s.notify(); //唤醒t1 } } } } ----------------------------------------------------------------------- public static void main(String[] args) { //创建资源 Student s = new Student(); //设置和获取的类 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //线程类 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //启动线程 t1.start(); t2.start(); }* 线程组: 把多个线程组合到一起。 * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
// 线程类里面的方法:public final ThreadGroup getThreadGroup() 获得当前线程所属的线程组
// 线程组里面的方法:public final String getName()
// 线程默认情况下属于main线程组,默任情况下,所有的线程都属于同一个组
public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } } ----------------------------------------------------------------- private static void method2() { // ThreadGroup(String name) ThreadGroup tg = new ThreadGroup("这是一个新的组"); MyRunnable my = new MyRunnable(); // Thread(ThreadGroup group, Runnable target, String name) Thread t1 = new Thread(tg, my, "林青霞"); Thread t2 = new Thread(tg, my, "狗蛋"); System.out.println(t1.getThreadGroup().getName()); System.out.println(t2.getThreadGroup().getName()); //通过组名称设置后台线程,表示该组的线程都是后台线程 tg.setDaemon(true); }生产者消费者模型最终版
package cn.itcast_07; public class Student { private String name; private int age; private boolean flag; // 默认情况是没有数据,如果是true,说明有数据 public synchronized void set(String name, int age) { // 如果有数据,就等待 if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 设置数据 this.name = name; this.age = age; // 修改标记 this.flag = true; this.notify(); } public synchronized void get() { // 如果没有数据,就等待 if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 获取数据 System.out.println(this.name + "---" + this.age); // 修改标记 this.flag = false; this.notify(); } } ------------------------------------------------------------------------- public class GetThread implements Runnable { private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { while (true) { s.get(); } } } ------------------------------------------------------------------------------ public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("林青霞", 27); } else { s.set("刘意", 30); } x++; } } } -------------------------------------------------------------------------------- public static void main(String[] args) { //创建资源 Student s = new Student(); //设置和获取的类 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //线程类 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //启动线程 t1.start(); t2.start(); }线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 * 这里讲的有点少,可以看文档,例子挺全的 * 如何实现线程池的代码呢? * A:创建一个线程池对象,控制要创建几个线程对象。 * public static ExecutorService newFixedThreadPool(int nThreads) * B:这种线程池的线程可以执行: * 可以执行Runnable对象或者Callable对象代表的线程 * 做一个类实现Runnable接口。 * C:调用如下方法即可 * Future<?> submit(Runnable task) * <T> Future<T> submit(Callable<T> task)
public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } } ------------------------------------------------------------------------------------ public static void main(String[] args) { // 创建一个线程池对象,控制要创建几个线程对象。 // public static ExecutorService newFixedThreadPool(int nThreads) ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //结束线程池 pool.shutdown(); }创建线程的第三种方式
//Callable:是带泛型的接口。 //这里指定的泛型其实是call()方法的返回值类型。
public class MyCallable implements Callable { @Override public Object call() throws Exception { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } return null; } }案例:线程求和
public class MyCallable implements Callable<Integer> { private int number; public MyCallable(int number) { this.number = number; } @Override public Integer call() throws Exception { int sum = 0; for (int x = 1; x <= number; x++) { sum += x; } return sum; } } ----------------------------------------------------------------------- public static void main(String[] args) throws InterruptedException, ExecutionException { // 创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); // V get() Integer i1 = f1.get(); Integer i2 = f2.get(); System.out.println(i1); System.out.println(i2); // 结束 pool.shutdown(); }通过匿名对象的方式创建线程(了解即可,少见)
public static void main(String[] args) { new Thread(){ public void run() { for (int x = 0; x < 100; x++) { System.out.println("hello" + ":" + x); } } }.start(); new Thread(new Runnable() { public void run() { for (int x = 0; x < 100; x++) { System.out.println("hello" + ":" + x); } } }).start(); new Thread(new Runnable() { ---->这种方式相当于前两种方式加一块了,会采用子类的实现方式 public void run() { for (int x = 0; x < 100; x++) { System.out.println("hello" + ":" + x); } } }){ public void run(){ for (int x = 0; x < 100; x++) { System.out.println("world" + ":" + x); } } }.start(); }定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。 * 依赖Timer和TimerTask这两个类: * Timer:定时 * public Timer() * public void schedule(TimerTask task,long delay) ------->多少秒后执行task * public void schedule(TimerTask task,long delay,long period) ---------->多少秒后,每隔多长时间执行task. * public void cancel() * TimerTask:任务
案例:定时删除文件
class DeleteFolder extends TimerTask { @Override public void run() { File srcFolder = new File("demo"); deleteFolder(srcFolder); } // 递归删除目录 public void deleteFolder(File srcFolder) { File[] fileArray = srcFolder.listFiles(); if (fileArray != null) { for (File file : fileArray) { if (file.isDirectory()) { deleteFolder(file); } else { System.out.println(file.getName() + ":" + file.delete()); } } System.out.println(srcFolder.getName() + ":" + srcFolder.delete()); } } } public class TimerTest { public static void main(String[] args) throws ParseException { Timer t = new Timer(); String s = "2014-11-27 15:45:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = sdf.parse(s); t.schedule(new DeleteFolder(), d); } }线程的常见执行情况
常见的面试题
1:多线程有几种实现方案,分别是哪几种? 两种。 继承Thread类 实现Runnable接口 扩展一种:实现Callable接口。这个得和线程池结合。
2:同步有几种方式,分别是什么? 两种。 同步代码块 同步方法
3:启动一个线程是run()还是start()?它们的区别? start(); run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用 start():启动线程,并由JVM自动调用run()方法
4:sleep()和wait()方法的区别 sleep():必须指时间;不释放锁。 wait():可以不指定时间,也可以指定时间;释放锁。
5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中 因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。 而Object代码任意的对象,所以,定义在这里面。
6:线程的生命周期图 新建 -- 就绪 -- 运行 -- 死亡 新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡 建议:画图解释。
Runtime:每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。
public static void main(String[] args) throws IOException { Runtime r = Runtime.getRuntime(); r.exec("winmine"); r.exec("notepad"); r.exec("calc"); r.exec("shutdown -s -t 10000"); r.exec("shutdown -a"); }网络编程:就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
网络模型:计算机网络之间以何种规则进行通信,就是网络模型研究问题。
网络模型一般是指
OSI(Open System Interconnection开放系统互连)参考模型
TCP/IP参考模型
网络模型7层概述:
1.物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
2. 数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
3. 网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
4. 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5.会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
6.表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
7.应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。
网络通信的三要素
IP地址:InetAddress
网络中设备的标识,不易记忆,可用主机名
端口号
用于标识进程的逻辑地址,不同进程的标识
传输协议
通讯的规则
常见协议:TCP,UDP
IP地址的组成 :32位bit.
IP地址 = 网络号码+主机地址
A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
IP地址的分类: A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.X.X.X是保留地址,用做循环测试用的。 B类 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。 C类 192.0.0.1---223.255.255.254 192.168.X.X是私有地址 D类 224.0.0.1---239.255.255.254 E类 240.0.0.1---247.255.255.254
两个DOS命令: ipconfig 查看本机ip地址 ping 后面跟ip地址。测试本机与指定的ip地址间的通信是否有问题 特殊的IP地址: 127.0.0.1 回环地址(表示本机) x.x.x.255 广播地址 x.x.x.0 网络地址
端口号: 正在运行的程序的标识。 有效端口:0~65535,其中0~1024系统使用或保留端口。 协议: 通信的规则 UDP: 把数据打包 数据有限制 不建立连接 速度快 不可靠 TCP: 建立连接通道 数据无限制 速度慢 可靠
InetAddress的成员方法: * public static InetAddress getByName(String host):根据主机名或者IP地址的字符串表示得到IP地址对象
public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("192.168.0.1"); // 获取两个东西:主机名,IP地址 // public String getHostName() String name = address.getHostName(); // public String getHostAddress() String ip = address.getHostAddress(); System.out.println(name + "---" + ip); }socket网络编程之UDP
*DatagramSocket:发送、接收功能。
*DatagramPacket:封装数据的载体。
public class SocketSend { public static void main(String[] args) throws IOException { DatagramSocket ds = new DatagramSocket(); byte[] bys="hello world java".getBytes(); int length=bys.length; InetAddress address = InetAddress.getByName("192.168.0.101"); int port=10086; DatagramPacket dp = new DatagramPacket(bys, length,address,port); ds.send(dp); ds.close(); } } -------------------------------------------------------------------------------------- public class SocketReceive { public static void main(String[] args) throws IOException { DatagramSocket ds = new DatagramSocket(10086); byte[] bys=new byte[1024]; int length = bys.length; DatagramPacket dp = new DatagramPacket(bys, length); ds.receive(dp); //InetAddress address = dp.getAddress(); //String ip = address.getHostAddress(); byte[] bys2 = dp.getData(); int len=bys2.length; String msg=new String(bys2,0,len); System.out.println("传递的数据时:"+msg); ds.close(); } }socket网络编程之TCP
public class ClientDemo { public static void main(String[] args) throws IOException { Socket socket=new Socket("192.168.0.101", 10086); OutputStream os = socket.getOutputStream(); os.write("hello world java".getBytes()); socket.close(); } } ------------------------------------------------------- public class ServiceDemo { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(10086); Socket s = ss.accept(); InputStream in = s.getInputStream(); byte[] bys=new byte[1024]; int len=in.read(bys); String msg = new String(bys,0,len); String ip = s.getInetAddress().getHostAddress(); System.out.println(msg+ip); s.close(); } }案例:键盘输入,服务器输出,由此除了键盘可以定向到文件,从而实现文件的上传工作。
public class ClientDemo { public static void main(String[] args) throws IOException { Socket socket=new Socket("192.168.0.101", 10086); BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter w = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String line; while((line=r.readLine())!=null){ if(line.equals("886")){ break; } w.write(line); w.newLine(); w.flush(); } socket.close(); } } ------------------------------------------------------------------------------------ public class ServiceDemo { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(10086); Socket s = ss.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); String line; while((line=in.readLine())!=null){ System.out.println(line); } s.close(); } }问题:上传文件的时候总报这个错,看了看网上的说法都说是连接断了,后来发现文件名写错了a.txt写成了a.java,错不难找,但是提示给的太笼统了。
案例:上传案例
*写完之后读操作,需要使用 public void shutdownOutput(),告知服务端我写完了。
public class ClientDemo { public static void main(String[] args) throws IOException, InterruptedException { Socket s=new Socket("192.168.0.101", 11111); BufferedReader br = new BufferedReader(new FileReader("D:\\temp\\a.txt")); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String msg=null; while((msg=br.readLine())!=null){ bw.write(msg); bw.newLine(); bw.flush(); } s.shutdownOutput();//服务端不识别null,通知服务端写完了。 BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream())); String reply = br2.readLine(); System.out.println(reply); br.close(); s.close(); } } ---------------------------------------------------------------------------------------- public class ServiceDemo { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(11111); Socket s = ss.accept(); BufferedWriter w = new BufferedWriter(new FileWriter("D:\\temp\\new.txt")); BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream())); String line=null; while((line=r.readLine())!=null){ w.write(line); w.newLine(); w.flush(); } BufferedWriter w2 = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); w2.write("上传完成!"); w2.newLine(); w2.flush(); w.close(); s.close(); } }JDK5新特性
自动装箱和拆箱
泛型
增强for循环
静态导入 import static 包名.类名.静态成员变量;
可变参数
枚举
枚举概述:是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天
自定义枚举有多麻烦。。。
package cn.itcast_01; public abstract class Direction3 { // 创建几个实例 public static final Direction3 FRONT = new Direction3("前") { @Override public void show() { System.out.println("前"); } }; public static final Direction3 BEHIND = new Direction3("后") { @Override public void show() { System.out.println("后"); } }; public static final Direction3 LEFT = new Direction3("左") { @Override public void show() { System.out.println("左"); } }; public static final Direction3 RIGHT = new Direction3("右") { @Override public void show() { System.out.println("右"); } }; // 构造私有,别人就不能无限的创建了 private Direction2() { } // 加入成员变量,并去掉无参构造 private String name; private Direction3(String name) { this.name = name; } public String getName() { return name; } // 加入抽象方法 public abstract void show(); }使用枚举,熟悉方法的话去看文档。
注意事项
•定义枚举类要用关键字enum
•所有枚举类都是Enum的子类 ,所以要实现其中的抽象方法。
•枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
•枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举(“”);
•枚举类也可以有抽象方法,但是枚举项必须重写该方法
•枚举在switch语句中的使用
public enum Direction3 { FRONT("前") { @Override public void show() { System.out.println("前"); } }, BEHIND("后") { @Override public void show() { System.out.println("后"); } }, LEFT("左") { @Override public void show() { System.out.println("左"); } }, RIGHT("右") { @Override public void show() { System.out.println("右"); } }; private String name; private Direction3(String name) { this.name = name; } public String getName() { return name; } public abstract void show(); }常用方法
public static void main(String[] args) { Direction3 d=Direction3.FRONT; Direction3 d1=Direction3.BEHIND; Direction3 d2=Direction3.LEFT; Direction3 d3=Direction3.RIGHT; System.out.println(d.ordinal());//0 System.out.println(d1.ordinal());//1 System.out.println(d2.ordinal());//2 System.out.println(d3.ordinal());//3 System.out.println(d.compareTo(d1));//-1 System.out.println(d.getName());//前 System.out.println(d.toString());//FRONT Direction3 right = Enum.valueOf(Direction3.class, "RIGHT"); Direction3[] dirs = Direction3.values(); for (Direction3 d5 : dirs) { System.out.println(d5.getName());//前 后 左 右 } }JDK7新特性
二进制字面量
数字字面量可以出现下划线
switch 语句可以用字符串
泛型简化
异常的多个catch合并
try-with-resources 语句
int a=0b1001; System.out.println(a); int b=034; System.out.println(b); int c=0x12; System.out.println(c); // 数字字面量可以出现下划线,不能作为开头和结尾 System.out.println(5_5_6); System.out.println(12.3_5); //泛型简化 ArrayList<String> array = new ArrayList<>();--------------------------------------------------------------结束---------------------------------------------------------------
类的加载 :当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
•加载
•就是指将class文件读入内存,并为之创建一个Class对象。
•任何类被使用时系统都会建立一个Class对象。
•连接
•验证 是否有正确的内部结构,并和其他类协调一致
•准备 负责为类的静态成员分配内存,并设置默认初始化值
•解析 将类的二进制数据中的符号引用替换为直接引用
•初始化 就是我们以前讲过的初始化步骤
类的初始化时机
创建类的实例
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
类加载器
•负责将.class文件加载到内在中,并为之生成对应的Class对象。
•虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
类加载器的组成
•Bootstrap ClassLoader 根类加载器 ,负责Java核心类的加载比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
•Extension ClassLoader 扩展类加载器 ,负责JRE的扩展目录中jar包的加载,l在JDK中JRE的lib目录下ext目录
•Sysetm ClassLoader 系统类加载器 ,负责在JVM启动时加载来自java命令的class文件,负责在JVM启动时加载来自java命令的class文件
反射:对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
有点破坏封装
常用方法
获取构造方法
getConstructors () 获得所有的共有的构造
getDeclaredConstructors () 获取所有的构造
获取单个公有的构造方法 public Constructor<T> getConstructor(Class<?>... parameterTypes) --->String.class...声明类型即可。
获得私有的构造和上边一样只要加Declared就可以了。。
创建对象
newInstance()
获取所有成员
getFields , getDeclaredFields
获取单个成员
getField , getDeclaredField
修改成员的值
set(Object obj,Object value)
获取所有方法
getMethods
getDeclaredMethods
获取单个方法
getMethod
getDeclaredMethod
执行方法
m.invoke(obj, "hello");
暴力访问
method.setAccessible(true);
获取class文件对象的方式: * A:Object类的getClass()方法 * B:数据类型的静态属性class * C:Class类中的静态方法 * public static Class forName(String className)
Person p = new Person(); Class c = p.getClass(); Person p2 = new Person(); Class c2 = p2.getClass(); System.out.println(p == p2);// false System.out.println(c == c2);// true ——----->class对象有自己的内存区 Class c3 = Person.class; System.out.println(c == c3); //true案例:在Integer的ArrayList中添加字符串
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { ArrayList<Integer> array = new ArrayList<Integer>(); Class c = array.getClass(); Method m = c.getMethod("add", Object.class); m.invoke(array, "hello"); m.invoke(array, "world"); System.out.println(array); }先编译,下面是反编译之后的版本
public static void main(String args[]) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { ArrayList arraylist = new ArrayList(); Class class1 = arraylist.getClass(); Method method = class1.getMethod("add", new Class[] { java/lang/Object }); method.invoke(arraylist, new Object[] { "hello" }); method.invoke(arraylist, new Object[] { "world" }); System.out.println(arraylist); }案例:通过一个文件来运行类中的方法,必须得知道文件中的内容。
className=cn.itcast.test.Worker methodName=love ------------------------------------------------------- public class Worker { public void love() { System.out.println("爱生活,爱老婆"); } } ------------------------------------------------------- public static void main(String[] args) throws Exception { // 加载键值对数据 Properties prop = new Properties(); FileReader fr = new FileReader("class.txt"); prop.load(fr); fr.close(); // 获取数据 String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); // 反射 Class c = Class.forName(className); Constructor con = c.getConstructor(); Object obj = con.newInstance(); // 调用方法 Method m = c.getMethod(methodName); m.invoke(obj); }案例:跳过get\set直接通过Tool普通方法,设置属性值
public class Tool { public void setProperty(Object obj, String propertyName, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { // 根据对象获取字节码文件对象 Class c = obj.getClass(); // 获取该对象的propertyName成员变量 Field field = c.getDeclaredField(propertyName); // 取消访问检查 field.setAccessible(true); // 给对象的成员变量赋值为指定的值 field.set(obj, value); } } ------------------------------------------------------------------------------- public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Person p = new Person(); Tool t = new Tool(); t.setProperty(p, "name", "林青霞"); t.setProperty(p, "age", 27); System.out.println(p); }动态代理:在程序运行过程中产生的这个对象
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib
Proxy类中的方法创建动态代理类对象
•public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
•最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)
public interface StudentDao { public abstract void login(); public abstract void regist(); } ------------------------------------------------- public class StudentDaoImpl implements StudentDao { @Override public void login() { System.out.println("登录功能"); } @Override public void regist() { System.out.println("注册功能"); } } --------------------------------------------------- public class MyInvocationHandler implements InvocationHandler { private Object target; // 目标对象 public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("权限校验"); Object result = method.invoke(target, args); System.out.println("日志记录"); return result; // 返回的是代理对象 } } ------------------------------------------------------------------- public static void main(String[] args) { StudentDao sd = new StudentDaoImpl(); MyInvocationHandler handler2 = new MyInvocationHandler(sd); StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass() .getClassLoader(), sd.getClass().getInterfaces(), handler2); proxy2.login(); proxy2.regist(); }