java 7 socket_JAVASE(七)--注解&反射&内部类&Socket

注解Annotation

注解很厉害,它可以增强我们的java代码,同时利用反射技术可以扩充实现很多功能。它们被广泛应用于三大框架底层。传统我们通过xml文本文件声明方式,而现在最主流的开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读。例如最火爆的SpringBoot就完全基于注解技术实现。JDK注解

@Override

@Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期

@SuppressWarnings(“deprecation”) 忽略警告

@SafeVarargs jdk1.7出现,堆污染,不常用

@FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用元注解

@Target 注解用在哪里:类上、方法上、属性上

@Retention 注解的生命周期:源文件中、class文件中、运行中

@Inherited 允许子注解继承

@Documented 生成javadoc时会包含注解,不常用

@Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用

@Target

用于指定被修饰注解的修饰目标类型。如果一个注解明确了可修饰的目标类型,则只能修饰指定的类型。由枚举ElementType来规定。

--ElementType.ANNOTATION_TYPE 应用于

--ElementType.CONSTRUCTOR 应用于构造函数

--ElementType.FIELD 应用于字段或属性

--ElementType.LOCAL_VARIABLE 应用于局部变量

--ElementType.METHOD 应用于方法级

--ElementType.PACKAGE 应用于包声明

--ElementType.PARAMETER 应用于方法的参数

--ElementType.TYPE 应用于类的元素

@Retention

定义了该注解被保留的时间长短,某些注解仅出现在源代码中,而被编译器丢弃;

而另一些却被编译在class文件中; 编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。

--SOURCE 在源文件中有效(即源文件保留)

--CLASS 在class文件中有效(即class保留)

--RUNTIME 在运行时有效(即运行时保留)

测试自定义注解import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

//测试 自定义注解

public class Test_Annotation {

public static void main(String[] args) {

}

}

//一,自定义注解: @interface 注解名

//@Target(ElementType.TYPE)//描述注解可以出现的位置--只能类上用

@Target({ ElementType.TYPE, ElementType.METHOD })//描述注解可以出现的位置--多个位置上用

@Retention(RetentionPolicy.SOURCE)//描述注解的生命周期

@interface Test{

//1,给注解添加功能--属性--语法特殊

//String local();

String local() default "" ;//3,给属性设置默认值,方便直接使用@Test

String value() default "" ; //5,特殊的属性value

}

//二,使用注解: @Test

//@Test(local = "class")//2,当Test注解添加了属性时,而且,属性又没设置默认值时,需要给属性赋值

//@Test//4,由于属性设置好了默认值,用时就简单了

@Test("123")//6,由于value属性比较特殊,可以简写.赋值时省略掉value=

class Hello{

//@Test//位置非法,不能出现

String name;

@Test(local = "method",value = "???")//7,给多个属性赋值时,不能省略value=

public void show(){

System.out.println("show()");

}

}

反射Reflect

Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。

反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。

反射常用方法获得包名、类名

clazz.getPackage().getName()//包名

clazz.getSimpleName()//类名

clazz.getName()//完整类名成员变量定义信息

getFields()//获得所有公开的成员变量,包括继承的变量

getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括继承的变量

getField(变量名)

getDeclaredField(变量名)构造方法定义信息

getConstructor(参数类型列表)//获得公开的构造方法

getConstructors()//获得所有公开的构造方法

getDeclaredConstructors()//获得所有构造方法,包括私有

getDeclaredConstructor(int.class, String.class)方法定义信息

getMethods()//获得所有可见的方法,包括继承的方法

getMethod(方法名,参数类型列表)

getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法

getDeclaredMethod(方法名, int.class, String.class)反射新建实例

c.newInstance();//执行无参构造

c.newInstance(6, "abc");//执行有参构造

c.getConstructor(int.class, String.class); //执行含参构造,获取构造方法反射调用成员变量

c.getDeclaredField(变量名); //获取变量

c.setAccessible(true); //使私有成员允许访问

f.set(实例, 值); //为指定实例的变量赋值,静态变量,第一参数给 null

f.get(实例); //访问指定实例的变量的值,静态变量,第一参数给 null反射调用成员方法

Method m = c.getDeclaredMethod(方法名, 参数类型列表);//获取方法

m.setAccessible(true) ;//使私有方法允许被调用

m.invoke(实例, 参数数据) ;//让指定的实例来执行该方法import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.util.Arrays;

//测试 反射 获取Class对象

public class Test_ReflectStudent {

public static void main(String[] args) throws Exception {

method();//获取Class对象

method2();//获取构造方法

method3();//获取成员方法

method4();//获取成员变量

method5();// 通过反射的技术创建对象

}

// 创建对象

public static void method5() throws Exception {

// 1,获取Class对象

Class clazz = Student.class;

// 2,调用实例化方法 --也要触发构造方法,而且触发的是无参构造

// newInstance()必须提供无参构造,否则[抛出异常:java.lang.InstantiationException:

// cn.tedu.reflect.Student

Student s = clazz.newInstance();

System.out.println("s = " + s);

// 重写toString()前:s = cn.tedu.reflect.Student@1b6d3586

// 重写toString()后:s = Student{name='null', age=0, score=0.0}

// 怎么触发含参构造--触发public Student(String name)

// getConstructor(m);--m参数要 匹配构造方法里 参数的类型 的Class对象

Constructor c = clazz.getConstructor(String.class);// 指定

// newInstance(x)--x是你创建对象时具体的参数

Student s2 = c.newInstance("jack");

System.out.println("s2 = " + s2);

// TODO 触发public Student(String name, int age)

Constructor c2 = clazz.getConstructor(String.class, int.class);

Student s3 = c2.newInstance("xiongda", 20);

System.out.println("s3 = " + s3);

}

// 获取成员变量

public static void method4() {

// 1,获取Class对象

Class clazz = Student.class;

// 2,获取所有成员变量 -- 只能获取公开的变量

Field[] fs = clazz.getFields();

// 3,遍历数组,得到每个变量f

for (Field f : fs) {

// 4,获取变量名称

System.out.println(f.getName());

// 5,获取变量类型

System.out.println(f.getType().getName());

}

}

// 获取成员方法

public static void method3() {

// 1,获取Class对象

Class clazz = Student.class;

// 2,获取所有成员方法们 -- 包括自己的和父类的 的公开的方法们

Method[] ms = clazz.getMethods();

// 3,遍历数组,得到每个方法m

for (Method m : ms) {

// 4,获取方法名称

System.out.println(m.getName());

// 5,获取方法的参数的类型

Class>[] cs = m.getParameterTypes();

System.out.println(Arrays.toString(cs));

}

}

// 获取构造方法

public static void method2() {

// 1,获取Class对象 --封装了.class文件里的所有数据

Class clazz = Student.class;

// 2,获取所有构造方法们 , 并存入数组 -- 只能反射 公开的 资源

Constructor[] cs = clazz.getConstructors();

// 3,获取每个构造方法c

for (Constructor c : cs) {

// 4,获取构造方法的名字

System.out.println(c.getName());

// 5,获取构造方法的参数类型 们

Class[] css = c.getParameterTypes();

System.out.println(Arrays.toString(css));

}

}

// 获取Class对象

public static void method() throws ClassNotFoundException {

Class c = Class.forName("cn.tedu.reflect.Student");// 参数是类的全路径

Class c2 = Student.class;

Class c3 = new Student().getClass() ;//使用了父类Object提供的getClass()

System.out.println("c3 = " + c3);

System.out.println("c2 = " + c2);

System.out.println("c = " + c);

}

}

暴力反射

不仅能获取到类的public资源,也可以获取到类里的private资源普通反射

--getConstructor()

--getConstructors()

--getMethod()

--getMethods()

--getField()

--getFields()暴力反射

--getDeclaredConstructor()

--getDeclaredConstructors()

--getDeclaredMethod()

--getDeclaredMethods()

--getDeclaredField()

--getDeclaredFields()import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.util.Arrays;

//测试 暴力反射:

//条件 : 使用getDeclaredXxx() + 开启私有可见的权限

public class Test_BaoliReflect {

public static void main(String[] args) throws Exception {

method();//暴力反射成员方法们

method2();// 暴力反射成员变量

}

// 暴力反射成员变量们

public static void method2() throws Exception {

// 1,获取Class对象

Class clazz = Person.class;

// 2,暴力反射

Field[] fs = clazz.getDeclaredFields();

// 3,遍历数组,得到每个变量f

for (Field f : fs) {

// 4,获取变量名称

System.out.println(f.getName());

// 5,获取变量类型

System.out.println(f.getType().getName());

}

// 获取指定的变量

Field f = clazz.getDeclaredField("score");

// 开启 访问权限,否则访问私有抛出异常:IllegalAccessException:

f.setAccessible(true);

Object obj = clazz.newInstance();

// 设置值--set(1,2)--1是指对象名称--2是要设置的具体值

f.set(obj, 99.9);

// 获取值--get(1)--1是指对象名称

System.out.println(f.get(obj));

}

// 暴力反射成员方法们

public static void method() throws Exception {

// 1,获取Class对象

Class clazz = Person.class;

// 2,暴力反射 -- getDeclaredMethods()

Method[] ms = clazz.getDeclaredMethods();

// 3,遍历数组,得到每个方法m

for (Method m : ms) {

// 4,获取方法名称

System.out.println(m.getName());

// 5,获取方法的参数的类型

Class>[] cs = m.getParameterTypes();

System.out.println(Arrays.toString(cs));

}

// 暴力反射 某个方法

// getDeclaredMethod(1,2)--获取指定的方法

// --1是指方法名--2是指方法需要的参数类型的Class对象

Method m = clazz.getDeclaredMethod("game", String.class);

// 暴力反射:除了用对API,另外还需要开启访问权限

m.setAccessible(true);

Object obj = clazz.newInstance();

// 执行方法--invoke(1,2)--1是指对象名称--2是方法需要传入的参数

m.invoke(obj, "tony");

}

}

内部类

如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。就是把类定义在类的内部的情况就可以形成内部类的形式。

A类中又定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。特点

1、 内部类可以直接访问外部类中的成员,包括私有成员

2、 外部类要访问内部类的成员,必须要建立内部类的对象

3、 在成员位置的内部类是成员内部类

4、 在局部位置的内部类是局部内部类//测试 内部类

public class Test_Inner {

public static void main(String[] args) {

// TODO 调用内部类的资源 --创建内部类对象

// 语法: 外部类名.内部类名 变量名 = 外部类对象.内部类对象

Outer.Inner in = new Outer().new Inner();

in.in();

System.out.println(in.age);

}

}

class Outer {// 外部类

String name = "jack";

public void out() {

// 3,外部类 访问内部类的 成员 -- 不可以直接用,需要创建内部类对象

new Inner().in();

System.out.println("out()");

}

// 1,内部类--可以看做是外部类的一个特殊成员,和其他成员是同级关系

class Inner {

int age = 20;

public void in() {

// 2,内部类 访问外部类 的成员 ?-- 可以

System.out.println(name);

System.out.println("in()");

}

}

}

匿名内部类

匿名内部类属于局部内部类,并且是没有名字的内部类。//测试 匿名内部类

//总结

//1,接口也可以直接new,但是要配合 匿名 内部类 ,完成抽象方法的重写 !!

public class Test_Inner2 {

public static void main(String[] args) {

// TODO 2,优化方案:直接new接口,要配合匿名内部类使用(在内部类里重写抽象方法)!!

new Inter() {

@Override

public void save() {

System.out.println("数据保存成功!");

}

@Override

public void delete(int id) {

System.out.println("数据删除成功!,id是:" + id);

}

}.save();// 调用指定方法

// 4,给匿名对象起个名字 !!! -- 方便使用同一个对象干多个事情 !!!

Inter in = new Inter() {

@Override

public void save() {

System.out.println("数据保存成功!");

}

@Override

public void delete(int id) {

System.out.println("数据删除成功!,id是:" + id);

}

};

// 5,使用有名字的同一个对象 ,干两件事

in.save();

in.delete(10);

}

}

interface Inter{

//简写形式

void save() ;

void delete(int id);

}

//TODO 1,可以优化 ...

class InterImpl implements Inter{

@Override

public void save() {

System.out.println("数据保存成功!");

}

@Override

public void delete(int id) {

System.out.println("数据删除成功!,id是:"+id);

}

}

Socket编程

在网络间,完成数据的传输. 把数据抽象的在网络间传递.对于电脑来讲,都可以完成收和发的过程.socket通信,本质上就是把数据 抽象成 IO流的形式在网路中传输.

服务器端-ServerSocket

在服务器端,选择一个端口号,在指定端口上等待客户端发起连接。

启动服务:ServerSocket ss = new ServerSocket(端口);

等待客户端发起连接,并建立连接通道:Sokcet socket = ss.accept();import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.Scanner;

//socket通信的服务器端

public class Server {

public static void main(String[] args) throws IOException {

// 1,开启服务器 -- 端口号0~65535

// 在指定的8000端口号处,等待客户端的连接

ServerSocket server = new ServerSocket(8000);

System.out.println("服务器已开启...");

// 2,接收客户端连接请求,并建立通信通道Socket

Socket socket = server.accept();

System.out.println("接收一个客户端的请求...");

// 3,读取客户端发来的数据

InputStream in = socket.getInputStream();

// 读到的数据默认是int,转成字符类型

for (int i = 0; i < 5; i++) {

char b = (char) in.read();

System.out.print(b);// 同行展示

}

// 4,服务器给客户端发送数据

OutputStream out = socket.getOutputStream();

// 写出 动态的 数据

System.out.println("请输入想要发送给客户端的数据:");

String input = new Scanner(System.in).nextLine();

out.write(input.getBytes());// String->byte[]

out.flush();

}

}

客户端-Socket

新建Socket对象,连接指定ip的服务器的指定端口

Socket s = new Socket(ip, port);

从Socket获取双向的流

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

import java.util.Scanner;

//socket通信的客户端

public class Client {

public static void main(String[] args) throws IOException {

// 1,连接 定 ip地址 和 端口 的服务器

// 实际工作中,要写服务器的真实ip -- 本机ip--127.0.0.1

Socket socket = new Socket("127.0.0.1", 8000);

System.out.println("客户端与服务器连接成功...");

// 2,给服务器写出数据

OutputStream out = socket.getOutputStream();

// 写出 动态的 数据

System.out.println("请输入想要发送给服务器的数据:");

String input = new Scanner(System.in).nextLine();

out.write(input.getBytes());// String->byte[]

out.flush();

// 3,读取服务器发来的数据

InputStream in = socket.getInputStream();

// 读到的数据默认是int,转成字符类型

for (int i = 0; i < 5; i++) {

char b = (char) in.read();

System.out.print(b);// 同行展示

}

}

}

jdk的新特性

JDK 5

可变长参数(Varargs)import java.util.Arrays;

//测试 jdk的新特性

// 1.5 --可变长 参数(Varargs)

public class TestJDK {

public static void main(String[] args) {

// method();

method(5);

method(5,10);

method(5,10,20);

method(5,10,20,6);

}

//TODO 优化: 提供一个method() ,但是可以动态 匹配 N 个参数

//TODO jdk1.5提供了可变长度的参数 ,根部不限制参数的个数.几个都行.可以省略 ,语法就是 类型后面加...

public static void method(int a,int... b){

//TODO 可变参数,本质上 是个数组,可以没有也可以有多个

//TODO 细节:可变参数 必须是参数列表的最后一个,这时,会把第一个参数匹配给a,剩下的都给b

System.out.println( Arrays.toString(b) );

}

}[]

[10]

[10, 20]

[10, 20, 6]

JDK 7

--switch 语句支持 String:switch语句块中允许以字符串作为分支条件

--类型推断:创建泛型对象时应用类型推断

--try-with-resources:自动关闭流

--catch 多个类型异常:一个语句块中捕获多种异常import java.io.*;

//测试 jdk的新特性

//jdk1.7 -- try-with-resources:自动关闭流 -- 自动资源管理

public class TestIO {

public static void main(String[] args) {

method();//字节流读取

method2();

}

public static void method2() {

// TODO jdk1.7 新语法实现了IO的自动资源管理:

// 优化了释放资源的动作,直接把声明的代码放在try的小括号里就行

try (InputStream in = new BufferedInputStream(new FileInputStream(""));) {

// 1,创建对象

// 2,正式读取

int b = in.read();

System.out.println("b = " + b);

} catch (Exception e) {

e.printStackTrace();

}

}

//字节流读取

public static void method() {

InputStream in = null ;//2,声明变量,因为finally也要用

try {

//1,创建对象

in = new BufferedInputStream(new FileInputStream(""));

//2,正式读取

int b = in.read() ;

System.out.println("b = " + b);

//TODO jdk1.7新语法提供 : 可以一次catch多个类型 的异常 ,中间用 | 分隔

}catch (ArithmeticException | IOException e){

e.printStackTrace();

} finally { //1,写一定要被执行的代码,否则发生异常时,异常后面的代码根部不会执行!!

//3,释放资源

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

JDK 8

Lambda 表达式 ? Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)//测试 jdk的新特性

//1.8 --Lambda表达式

//使用Lambda语法来代替 匿名内部类,代码不仅简洁,而且还可读

//语法: (参数列表) -> { 方法体 }

//要求: --只有一个抽象方法的 接口

public class TestLambda {

public static void main(String[] args) {

// TODO Lambda表达式--要求接口里只能有一个抽象方法--优化匿名内部类

// TODO 语法:(参数列表) -> { 方法体 } ; --练习:没有参数,没有返回值

Inter in2 = () -> {

System.out.println("Lambda表达式!");

};

in2.save();

// TODO 语法:(参数列表) -> { 方法体 } ; --练习:有参数,没有返回值

Inter2 in3 = (int a) -> {

System.out.println(a);

};

in3.delete(10);

// TODO 语法:(参数列表) -> { 方法体 } ; --练习:有参数,有返回值(使用return关键字)

Inter3 in4 = (String a, int b) -> {

return a + b;

};

System.out.println(in4.get("张三", 18));// 打印获取到的结果

}

}

interface Inter3{

String get(String name,int age);

}

interface Inter2{

void delete(int id) ;

}

interface Inter{

void save() ;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值