JAVA笔记(十五)
- 键盘录入对象,要自定义结束标志,如果是文件,就不必定义结束文件。
-
Tcp协议代码 package cn.itcast_06; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; /* * TCP协议发送数据: * A:创建发送端的Socket对象 * 这一步如果成功,就说明连接已经建立成功了。 * B:获取输出流,写数据 * C:释放资源 * * 连接被拒绝。TCP协议一定要先看服务器。 * java.net.ConnectException: Connection refused: connect */ public class ClientDemo { public static void main(String[] args) throws IOException { // 创建发送端的Socket对象 // Socket(InetAddress address, int port) // Socket(String host, int port) // Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888); Socket s = new Socket("192.168.12.92", 8888); // 获取输出流,写数据 // public OutputStream getOutputStream() OutputStream os = s.getOutputStream(); os.write("hello,tcp,我来了".getBytes()); // 释放资源 s.close(); } }
package cn.itcast_06; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /* * TCP协议接收数据: * A:创建接收端的Socket对象 * B:监听客户端连接。返回一个对应的Socket对象 * C:获取输入流,读取数据显示在控制台 * D:释放资源 */ public class ServerDemo { public static void main(String[] args) throws IOException { // 创建接收端的Socket对象 // ServerSocket(int port) ServerSocket ss = new ServerSocket(8888); // 监听客户端连接。返回一个对应的Socket对象 // public Socket accept() Socket s = ss.accept(); // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。 // 获取输入流,读取数据显示在控制台 InputStream is = s.getInputStream(); byte[] bys = new byte[1024]; int len = is.read(bys); // 阻塞式方法 String str = new String(bys, 0, len); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip + "---" + str); // 释放资源 s.close(); // ss.close(); //这个不应该关闭 } } 多线程tcp传输代码 package cn.itcast_15; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; public class UserThread implements Runnable { private Socket s; public UserThread(Socket s) { this.s = s; } @Override public void run() { try { // 封装通道内的流 BufferedReader br = new BufferedReader(new InputStreamReader( s.getInputStream())); // 封装文本文件 // BufferedWriter bw = new BufferedWriter(new // FileWriter("Copy.java")); // 为了防止名称冲突 String newName = System.currentTimeMillis() + ".java"; BufferedWriter bw = new BufferedWriter(new FileWriter(newName)); String line = null; while ((line = br.readLine()) != null) { // 阻塞 bw.write(line); bw.newLine(); bw.flush(); } // 给出反馈 BufferedWriter bwServer = new BufferedWriter( new OutputStreamWriter(s.getOutputStream())); bwServer.write("文件上传成功"); bwServer.newLine(); bwServer.flush(); // 释放资源 bw.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } }
package cn.itcast_15; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; public class UploadClient { public static void main(String[] args) throws IOException { // 创建客户端Socket对象 Socket s = new Socket("192.168.12.92", 11111); // 封装文本文件 // BufferedReader br = new BufferedReader(new FileReader( // "InetAddressDemo.java")); BufferedReader br = new BufferedReader(new FileReader( "ReceiveDemo.java")); // 封装通道内流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( s.getOutputStream())); String line = null; while ((line = br.readLine()) != null) { // 阻塞 bw.write(line); bw.newLine(); bw.flush(); } // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了 s.shutdownOutput(); // 接收反馈 BufferedReader brClient = new BufferedReader(new InputStreamReader( s.getInputStream())); String client = brClient.readLine(); // 阻塞 System.out.println(client); // 释放资源 br.close(); s.close(); } } package cn.itcast_15; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class UploadServer { public static void main(String[] args) throws IOException { // 创建服务器Socket对象 ServerSocket ss = new ServerSocket(11111); while (true) { Socket s = ss.accept(); new Thread(new UserThread(s)).start(); } } }
- 三种获取Class对象的方法
A:三种获取Class对象的方式
1:Person p = new Person();
Class c = p.getClass();
2:Class c2 = Person.class;
任意数据类型都具备一个class静态属性,看上去要比第一种方式简单.
3:将类名作为字符串传递给Class类中的静态方法forName即可
Class c3 = Class.forName("Person");
4:第三种和前两种的区别
前两种你必须明确Person类型.
后面是你我这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了
package cn.itcast_01;
/*
* 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
* * Person p = new Person();
* p.使用
* * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
* Class类:
* 成员变量 Field
* 构造方法 Constructor
* 成员方法 Method
* * 获取class文件对象的方式:
* A:Object类的getClass()方法
* B:数据类型的静态属性class
* C:Class类中的静态方法
* public static Class forName(String className)
* 一般我们到底使用谁呢?
* A:自己玩 任选一种,第二种比较方便
* B:开发 第三种
* 为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
*/
public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { // 方式1 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 // 方式2 Class c3 = Person.class; // int.class; // String.class; System.out.println(c == c3); // 方式3 // ClassNotFoundException Class c4 = Class.forName("cn.itcast_01.Person"); System.out.println(c == c4); } }
- 反射正常情况下是不能访问私有的,但是可以通过setAccessible()方法就可以访问了(暴力访问,取消访问检查),该方法要放在实际调用之前。
- 通过反射获取方法有点特殊,不加Declared,获取的是父类和自己的公共方法,加了获取的是自己的方法。
- 泛型的默认类型是object类型,泛型是给编译器看得,运行的时候就不存在了。
- 开发的一个原则是:对修改关闭,对扩展开放。
- 动态代理
在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)
Proxy类中创建动态代理对象的方法的三个参数;
ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke 方法来进行调用。
InvocationHandler接口中invoke方法的三个参数:
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表调用目标方法时传入的实参
Proxy.newProxyInstance
创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,
也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,
以$开头,proxy为中,最后一个数字表示对象的标号。
System.out.println(u.getClass().getName());
- 通过反射获取所有的方法
package cn.itcast_04; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReflectDemo { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("cn.itcast_01.Person"); // 获取所有的方法 // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法 // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法 // for (Method method : methods) { // System.out.println(method); // } Constructor con = c.getConstructor(); Object obj = con.newInstance(); /* * Person p = new Person(); p.show(); */ // 获取单个方法并使用 // public void show() // public Method getMethod(String name,Class<?>... parameterTypes) // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型 Method m1 = c.getMethod("show"); // obj.m1(); // 错误 // public Object invoke(Object obj,Object... args) // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数 m1.invoke(obj); // 调用obj对象的m1方法 System.out.println("----------"); // public void method(String s) Method m2 = c.getMethod("method", String.class); m2.invoke(obj, "hello"); System.out.println("----------"); // public String getString(String s, int i) Method m3 = c.getMethod("getString", String.class, int.class); Object objString = m3.invoke(obj, "hello", 100); System.out.println(objString); // String s = (String)m3.invoke(obj, "hello",100); // System.out.println(s); System.out.println("----------"); // private void function() Method m4 = c.getDeclaredMethod("function"); m4.setAccessible(true); m4.invoke(obj); } }
(原方法没有写出,获取构造方法和字段何其类似)
- 动态代理机制的代码
package cn.itcast_06; /* * 用户操作接口 */ public interface UserDao { public abstract void add();public abstract void delete(); public abstract void update();public abstract void find(); } package cn.itcast_06; public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("添加功能"); } @Override public void delete() { System.out.println("删除功能"); } @Override public void update() { System.out.println("修改功能"); } @Override public void find() { System.out.println("查找功能"); } } package cn.itcast_06; public interface StudentDao { public abstract void login();public abstract void regist(); } package cn.itcast_06; public class StudentDaoImpl implements StudentDao { @Override public void login() { System.out.println("登录功能"); } @Override public void regist() { System.out.println("注册功能"); } } package cn.itcast_06; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { UserDao ud = new UserDaoImpl(); ud.add();ud.delete();ud.update();ud.find(); System.out.println("-----------"); // 我们要创建一个动态代理对象 // Proxy类中有一个方法可以创建动态代理对象 // public static Object newProxyInstance(ClassLoader loader,Class<?>[] // interfaces,InvocationHandler h) // 我准备对ud对象做一个代理对象 MyInvocationHandler handler = new MyInvocationHandler(ud); UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass() .getClassLoader(), ud.getClass().getInterfaces(), handler); proxy.add();proxy.delete();proxy.update();proxy.find(); System.out.println("-----------"); 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(); } }
- 经典代码
package cn.itcast.test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; /* * 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢? */ public class ArrayListDemo { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 创建集合对象 ArrayList<Integer> array = new ArrayList<Integer>(); // array.add("hello"); // array.add(10); Class c = array.getClass(); // 集合ArrayList的class文件对象 Method m = c.getMethod("add", Object.class); m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello m.invoke(array, "world"); m.invoke(array, "java");System.out.println(array); } } 通过配置文件访问对象 package cn.itcast.test; import java.io.FileReader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Properties; /* * 通过配置文件运行类中的方法 ** 反射: * 需要有配置文件配合使用。 * 用class.txt代替。 * 并且你知道有两个键。 * className * methodName */ public class Test { public static void main(String[] args) throws Exception { // 反射前的做法 // Student s = new Student(); // s.love(); // Teacher t = new Teacher(); // t.love(); // Worker w = new Worker(); // w.love(); // 反射后的做法 // 加载键值对数据 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); } }
- 通过自定义方法给任意变量赋值代码
package cn.itcast.test; import java.lang.reflect.Field; 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); } } package cn.itcast.test; public class ToolDemo { 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); System.out.println("-----------");Dog d = new Dog() t.setProperty(d, "sex", '男');t.setProperty(d, "price", 12.34f);System.out.println(d); } }class Dog { char sex; float price; @Override public String toString() { return sex + "---" + price; } } class Person { private String name; public int age; @Override public String toString() { return name + "---" + age; } } 模式一般的方法
简单工厂模式和工厂方法模式(接口)模版设计模式(抽象类)
装饰设计模式(IO流)单例设计模式(多线程)适配器模式(GUI)
- 抽象类不能自己创建对象,假如要将创建对象,我们可以让子类赋值和父类(多态)代替。
- 枚举的格式及方法和注意事项。
格式是:只有枚举项的枚举类
public enum 枚举类名 {
枚举项1,枚举项2,枚举项3…;
}
注意事项
定义枚举类要用关键字enum所有枚举类都是Enum的子类
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举(“”);
枚举类也可以有抽象方法,但是枚举项必须重写该方法
枚举在switch语句中的使用
int compareTo(E o) String name() int ordinal()
String toString() <T> T valueOf(Class<T> type,String name)
values()
此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便
- Jdk7的一些新特性
jDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。使用二进制字面量的好处是,可以使代码更容易被理解。语法非常简单,只要在二进制数值前面加 0b或者0B
举例: int x = 0b110110
(是零不是欧)
为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。
举例:
int x = 100_1000;
注意事项:
不能出现在进制标识和数值之间
不能出现在数值开头和结尾
不能出现在小数点旁边
格式:
try(必须是java.lang.AutoCloseable的子类对象){…}
好处:
资源自动释放,不需要close()了
把需要关闭资源的部分都定义在这里就ok了
主要是流体系的对象是这个接口的子类(看JDK7的API)
package cn.itcast_03; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; public class Demo { public static void main(String[] args) { // 二进制字面量 int x = 0b100101; System.out.println(x); // 数字字面量可以出现下划线 int y = 1_1123_1000; // 不能出现在进制标识和数值之间 int z = 0x111_222; // 不能出现在数值开头和结尾 int a = 0x11_22; // 不能出现在小数点旁边 double d = 12.3_4; // switch 语句可以用字符串?自己回顾 // 泛型简化 ArrayList<String> array = new ArrayList<>(); // 异常的多个catch合并 method(); } private static void method() { // try-with-resources 语句 // try(必须是java.lang.AutoCloseable的子类对象){…} try { FileReader fr = new FileReader("a.txt"); FileWriter fw = new FileWriter("b.txt"); int ch = 0; while ((ch = fr.read()) != -1) { fw.write(ch); } fw.close(); fr.close(); } catch (IOException e) { e.printStackTrace(); } // 改进版的代码 try (FileReader fr = new FileReader("a.txt"); FileWriter fw = new FileWriter("b.txt");) { int ch = 0; while ((ch = fr.read()) != -1) { fw.write(ch); } } catch (IOException e) { e.printStackTrace(); } } } Jdk8的新特性代码 interface Inter { //抽象方法 public abstract void show(); //default方法 public default void defaultPrint() { System.out.println("defaultPrint 我爱林青霞"); } //static方法 public static void staticPrint() { System.out.println("staticPrint 我爱林青霞"); } } //实现类 class InterImpl implements Inter { public void show() { System.out.println("重写接口中的方法"); } } //测试类 public class Demo01 { public static void main(String[] args) { //Inter.defaultPrint(); //非静态方法不能直接使用 Inter.staticPrint(); Inter i = new InterImpl(); i.defaultPrint(); i.show(); } }