反射 & 注解 & 网络编程 & 路径
反射机制
概述
通过java语言中的反射机制,可以操作字节码文件 .class。
反射机制的相关类在 java.lang.reflect.* 包下
反射机制相关的重要的类
java.lang.Class 整个字节码文件,代表一个类型
java.lang.reflect.Method 字节码中的方法
java.lang.reflect.Constructor 字节码中的构造方法
java.lang.reflect.Field 字节码中的属性
获取字节码文件
要操作一个类的字节码文件,需要首先获取到这个类的字节码文件。
三种获取class文件方式
- 通过java.lang.Class类中的forName() 来获取
Class c1 = ``Class.forName("com.yixuexi.test01.Test");
注意
forName()是静态方法
方法的参数是一个字符串 必须是一个完整的类名【带包名】
返回一个Class类型对象
- java中任何一个对象,都有一个getClass()方法
Test test = new Test();
Class c2 = test.getClass();
java中任何一种类型,都有.class属性
Class c3 = Test.class;
c3代表 Test类型
注意:c3 == c1/c2 true 变量的内存地址相同
获取到Class后做的事情
通过newInstance()来实例化对象
Class c1 = Class.forName(“com.yixuexi.bean.User”);
Object obj = c1.newInstance();
底层会调用User的无参构造方法
如果写了有参构造,则默认的无参消失 报异常:java.lang.InstantiationException 实例化对象异常
Class.forName() 方法的执行
Class.forName("com.yixuexi.Test");
forName()方法 会导致类加载,类加载时会执行静态代码块
可变长度参数
语法:
public static void m(int... args){
}
类型后面跟3个点 …
- 可边长参数必须在形参列表中最后一个
- 可以当作一个数组来对待, 直接用for遍历args也可以
作用
调用时,传参可以 传 0-n个
通过反射机制得到Field(属性)了解
getFields()
Class c = Class.forName(“com.yixuexi.bean.Student”);
//获取类中所有的field,返回一个Field数组
Field[] arr = c.getFields();
// 返回对应下标的属性的名字
String fieldName = arr[0].getName();
获取类中所有(public ) 属性
getDeclaredFields()
- //获取全部的属性,不管是不是私有的 公开的
- Field[] f = c.getDeclaredFields();
f[0].getType()
获取对应属性的类型
Class s = f[0].getType(); //返回一个Class
System.out.println(s.getName()); // 通过getName得到名字【带包名】
System.out.println(s.getSimpleName()); //得到简单的类名
f[0].getModifiers()
- 返回对应属性的修饰符编号,每个数字是修饰符的代号
- 将代号数字转换成字符串: Modifier.toString(f[0].getModifiers()) 静态方法
getName() 得到这个属性的名字
通过反射机制访问对象属性(掌握)
设置(公开的)
//通过反射机制访问java对象的属性
Class c = Class.forName("com.yixuexi.bean.Student");
//通过反射机制创建一个对象
Object obj = c.newInstance();
//获取id属性,根据属性的名称获取Field
Field f = c.getDeclaredField("id");
//赋值 三要素:obj对象, id属性 1111值
f.set(obj,1111);// 给obj的id属性赋值1111
访问(公开的)
System.out.println(f.get(obj)); //访问obj的id属性
访问私有属性需打破封装
//打破封装
f.setAccessible(true);
在set或者get上面 添加这行代码
※反射机制调用方法
反射机制调用方法
//通过反射机制调用方法 获取类
Class c = Class.forName("com.yixuexi.bean.Student");
//创建对象
Object obj = c.newInstance();
//获取Method, 第一个参数是方法名,第二个是可变长度类型Class
Method doSomeMethod = c.getDeclaredMethod("doSome", String.class, int.class);
//调用方法 调用obj对象的 doSomeMethod方法,[传 "张三" 11 参数(可变长度)] 返回值为returnValue
Object returnValue = doSomeMethod.invoke(obj,"张三",11);
通过反射获取类的父类和父接口
Class c = Class.forName("java.lang.String");
//获取String的父类
Class superClass = c.getSuperclass();
System.out.println(superClass.getSimpleName());
//获取String实现的所有接口,返回Class数组
Class[] superInterfaces = c.getInterfaces();
for (Class superInterface : superInterfaces) {
System.out.println(superInterface);
}
注解
概述
- 属于引用数据类型
编译之后也是生成 xxx.class文件
语法格式:
修饰符列表 @interface 注解类名{
}
使用
- 注解使用的语法格式: @注解类型名
- 可以出现在 类上,方法上,变量上,注解类型上等
JDK内置的注解
出现在方法上,供编译器检查是否为重写的方法
并不是必须的
标注这个已经过时了, 有一个删除线
向其他程序员告诉已过时,有更好的解决方案
元注解
如果一个注解修饰一个注解类型, 那么他就叫元注解
常见的元注解
Target
一个元注解,用来标注“注解类型”的注解
标注:被标注的注解可以出现在哪些位置上
@Target({ElementType.METHOD}) : 表示被标注的注解只能出现在方法上
Retention
表示该注解最终保存到哪(保持性策略)
@Retention(RetentionPolicy.SOURCE) 表示该注解最后只会保存在java源文件中
@Retention(RetentionPolicy.CLASS) 保留在class文件中
@Retention(RetentionPolicy.RUNTIME) 保留在class文件中 并且可以被反射读取
在注解里面创建一个属性
public @interface MyAnnotation{
String name(); //属性 看着很奇怪,但就是这样
String color() default="默认"; //设置默认值
}
当使用这个注解的时候,需要这样使用(指定属性值)
@MyAnnotation(属性名=属性值,属性名=属性值)
public static void doSome(){}
如果属性名是value 是 String/int/… value() 那么在用这个注解的时候 直接 @MyAnnotation(“zhangsan”) value可以省略(只有一个value属性)
类型
byte short int long float double boolean char String Class 枚举
注解在开发时的作用
- 对程序的一种注释,一种标记
- 如果这个元素上有这个注解会怎么办,没有会怎么办
网络编程
什么是网络编程?
java提供的类库,可以实现顺滑的网络连接,联网的底层细节被隐藏,由JVM控制。并且java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境;
计算机网络是什么?
把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大,功能强的网络系统,从而使众多的计算机可以方便的交互传递信息、共享硬件、软件、数据信息等资源。
网络编程的目的?
直接或间接的通过网络协议与其他计算机实现数据交互,进行通讯
网络编程中两个主要的问题
- 如果准确的定位到网络中的一台或多台主机:定位主机上的应用(IP和端口号)
- 找到主机后如何可靠并高效的进行数据传输(TCP/IP模型【应用层,传输层,网络层,物理+数据链路层】)
IP/端口号(网络通信要素1)
IP:一个主机的位置
端口号:一个主机上不同的应用程序
ip分类(了解)
IP地址分类:ipv4和ipv6
Ipv4:4个字节组成,4个0-255,大概有42个,30亿都在北美,亚洲4个亿。2011年初已经用尽,以点十进制表示:192.168.0.1
Ipv6:6个字节组成(128位),写成8个无符号整数,每个整数用4个十六进制表示,数之间用冒号分开例如:3ffe:3201:1404:1280:c8ff:fe4d:db39:1934
ip地址分类:公网地址(万维网使用)和私有地址(局域网使用)
192.168.0.0-192.168.255.255 为私有地址【192.168开头的都是私有地址】
InetAddress类
实例化InetAddress(返回一个InetAddress对象)
InetAddress.getByName(“域名/IP地址”) // 返回一个 InetAddress对象【静态方法】
InetAddress.getLoaclHost(); //得到本机IP地址【静态方法】
本机回路地址 127.0.0.1 == localhost
InetAddress对象的常用方法
getHostName(); //得到域名
getHostAddress(); //得到IP
端口号
用来表示计算机上正在运行该的进程(不同的进程有不同的端口号)
被规定为一个16位的整数 0~65535
- 公认端口
0~1023 被预先定义的服务通信占用(Http占用端口:80,FTP:21 Telnet:23)
- 注册端口
1024~49151 分配给用户进程或应用程序(Tomcat:8080 MySQL:3306 Oracle:1521)
- 动态/私有端口
49152~65535
端口号与IP地址的组合得出来一个套接字(Socket 骚k t)
网络协议(网络通信要素2)
网络协议被分成好几层:应用层,传输层,网络层,物理+数据链路层
传输层中UDP和TCP的区别
TCP协议:
Ø 使用TCP协议前,先建立传输数据通道
Ø 传输前,采用“三次握手:方式,点对点通信,可靠。(三次握手,让双方知道 我在你也在)
Ø TCP协议进行通信的两个进程:客户端,服务端
Ø 在连接中可进行大数据量的传输
Ø 传输完毕,需要释放已建立的连接,效率低(四次挥手)
客户端(我要断开了)——>服务端(我接受到了)(我断开了)——->服务端(验证一下再发一条)
【QQ聊天】(打电话)
UDP协议:
Ø 将数据,源,目的地封装成数据包,不需要连接
Ø 每个数据报的大小为64kb内
Ø 发送不管对方是否准备好,接受方收到也不确认,所以不可靠
Ø 可以广播发送
Ø 发送数据结束时无需释放资源,开销小,速度快
【网络视频,直播】(发短信,发电报)
路径问题
获取文件绝对路径
以前
FileReader reader = new FileReader(“thread/peizhi”)
这种路径的缺点是:移植性差,在IDEA中默认的当前路径是project的根
假设离开了IDEA换到了其他位置,可能当前路径就不是当前project的根了,此时路径无效
通用
只适合文件放在类路径下的
什么是类路径:凡是在src下的都是类路径下
src是类的根路径
String path = Thread.currentThread().getContextClassLoader().getResource(“classinfo.properties”).getPath();
解释:
Thread.currentThread() // 得到当前线程对象
getContextClassLoader() // 是线程对象的方法,可以获取到当前线程的类加载器对象。
getResource() // 是类加载器的方法,当前线程的类加载器默认从类的根路径下加载资源。
适用于 linux系统
直接以流的方式返回
InputStream inputStream =
Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties");
直接返回一个InputStream流
资源绑定器
java.util.ResourceBundle 包下
实现
ResourceBundle resourceBundle = ResourceBundle.getBundle(“classinfo”);
通过key得到value
String value = resourceBundle.getString(“classname”);
// 得到对应的classname的value
注意
- 这里的后缀一定要去掉
- 只能绑定类路径下的配置文件(src下的 .properties文件)