JAVASE-注解+反射+内部类+socket+JDK新特性

1注解

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

分类:
1、JDK自带注解
2、元注解
3、自定义注解

JDK注解:
JDK注解的注解,就5个:
1、@Override
2、@Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
3、@SuppressWarnings(“deprecation”) 忽略警告
4、@SafeVarargs jdk1.7出现,堆污染,不常用
5、@FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用

元注解:
描述注解的注解,就5个:
1、@Target 注解用在哪里:类上、方法上、属性上

ElementType.FIELD 应用于字段或属性
ElementType.METHOD 应用于方法级
ElementType.TYPE 应用于类的元素

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

RetentionPolicy.RUNTIME 在运行时有效

3、@Inherited 允许子注解继承
4、@Documented 生成javadoc时会包含注解,不常用
5、@Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用

自定义注解:

//一,自定义注解:@interface  注解名
//描述注解可以出现的位置--多个位置上用
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)//描述注解的生命周期
@interface Test{
  //1,给注解添加功能--属性--语法特殊
  String local()default "";//3,给属性设置默认值,方便直接使用@Test
  String value();//5,特殊的属性value
}
//二,使用注解:@Test
//@Test(local="class")//2,当Test注解添加了属性时,需要给属性赋值
class taotao{
  String name;
//  @Test//4,由于属性设置好了默认值,用时就简单了
//  @Test("123")//6,由于value属性比较特殊,可以简写,赋值时省略掉value=
  @Test(local = "method",value="")//7,给多个属性赋值时,不能省略value=
  public  void show(){
      System.out.println("show()...");
  }
}

2反射

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

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

2.1创建对象

Class.forName(“类的全路径”);
类名.class
对象.getClass();

测试:

//方式1:        Class.forName("类的全路径");
        Class clazz = Class.forName("java.lang.String");
//方式2:        类名.class
        Class clazz2 = String.class;
//方式3:        对象.getClass();
        Class clazz3 = new String().getClass();

2.2常用方法

JAVASE-注解+反射+内部类+socket+JDK新特性_第1张图片
测试:

public static void main(String[] args) throws Exception {
//        method();//获取Class对象
//        method2();//获取构造方法
//        method3();//获取成员方法
//        method4();//获取成员变量
//        method5();//通过反射创建对象
    }
    public static void method5() throws Exception {
        //1,获取Class对象
        Class a = Test2_Student.class;
        //2,调用实例化方法 -- 也要触发构造方法,而且触发的是无参构造
        //java.lang.InstantiationException没有无参构造报异常
        Test2_Student as = a.newInstance();
        System.out.println("as="+as);
        //重写toString()前:as=day18.Test2_Student@15db9742
        //重写toString()后:as=Test2_Student [name=null, age=0, score=0.0]
        //怎么触发含参构造--匹配构造方法里 参数列表
        Constructor ass = a.getConstructor(String.class);//指定
        //X是创建对象时距离的参数
        Test2_Student ass2 = ass.newInstance("jack");
        System.out.println("ass2="+ass2);
        //创建2个参数的构造方法
        Constructor bss = a.getConstructor(String.class,int.class,double.class);
        Test2_Student bsss = bss.newInstance("taotao",20,20.1);
        System.out.println("bsss="+bsss);
    }
    //获取成员变量
    public static void method4() {
        //1,获取Class对象
        Class a = Test2_Student.class;
        //2,获取所有的成员变量--只能获取到public修饰的变量
        Field[] as = a.getFields();
        //3,遍历数组,得到每个变量ass
        for(Field ass:as) {
            //4,获取变量名
            System.out.println(ass.getName());
            //5,获取变量类型
            System.out.println(ass.getType().getName());
        }
    }
    //获取成员方法
    public static void method3() {
        //1,获取Class对象
        Class a = Test2_Student.class;
        //2,获取所有成员方法们 --包括自己的和父类的
        Method[] as = a.getMethods();
        //3,遍历数组,得到每个方法ass
        for(Method ass:as) {
            //4,获取方法名
            System.out.println(ass.getName());
            //5,获取方法的参数的类型
            Class[] asss = ass.getParameterTypes();
            System.out.println(Arrays.toString(asss));
        }
    }
    //获取构造方法
    public static void method2() {
        //1,获取Class对象 --封装了.class文件里的所有数据
        Class c1 = Test2_Student.class;
        //2,调用方法
//            --获得所有公开的构造方法,并存入数组
        Constructor[] cs = c1.getConstructors();
        //3,获取每个构造方法
        for(Constructor css:cs) {
            //4,获取构造方法的名字
            System.out.println(css.getName());
            //5,获取构造方法的参数
            Class[] css1=css.getParameterTypes();
            System.out.println(Arrays.toString(css1));
        }    
    }
    //获取Class对象
    public static void method() throws ClassNotFoundException {
//    Class.forName(“类的全路径”);
//    类名.class
//    对象.getClass();
        Class c = Class.forName("test.reflect.Test3_Reflect2");
        Class c1 = Test3_Reflect2.class;
        Class c2 = new Test3_Reflect2().getClass();
    }

2.3暴力反射

基本API:
JAVASE-注解+反射+内部类+socket+JDK新特性_第2张图片

    public static void main(String[] args) throws Exception {
//        method();//暴力反射成员方法们
//        method2();//暴力反射成员变量

    public static void method2() throws Exception {
        Class a = Person.class;
        Field[] as = a.getDeclaredFields();
        for(Field ass:as) {
            System.out.println(ass.getName());
            System.out.println(ass.getType().getName());
        }
        //获取指定的变量
        Field f = a.getDeclaredField("score");
        f.setAccessible(true);
        Object obj = a.newInstance();
        //设置值--set(1,2)--1是指对象名称,2是要设置的具体值
        f.set(obj, 20.0);
        //获取值--get(1)--1是指对象名称
        System.out.println(f.get(obj));
    }
    public static void method() throws Exception{
        //1,获取Class对象
        Class a = Person.class;
        //2,调用方法暴力反射
        Method[] as = a.getDeclaredMethods();
        //3,遍历数组,得到每个方法ass
        for(Method ass:as) {
            //4,获取方法名称
            System.out.println(ass.getName());
            //5,获取方法的参数的类型
            Class[] asss = ass.getParameterTypes();
            System.out.println(Arrays.toString(asss));    
        }
        //暴力反射 某个方法
        //getDeclaredMethod(1,2)--获取指定的方法
        //--1是指方法名--2是指方法需要的参数类型的Class对象
        Method m = a.getDeclaredMethod("game", String.class);
        Method m1 = a.getDeclaredMethod("eat");
        //暴力反射:除了用对API,另外还需要开启访问权限
        m.setAccessible(true);
        //执行方法--invoke(1,2)--1是指对象名称--2是方法需要传入的参数
        Object obj = a.newInstance();
        m1.invoke(obj, null);
//        m.invoke(obj, "张三");
    }

3内部类

概述:
如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。就是把类定义在类的内部的情况就可以形成内部类的形式。
A类中又定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。

特点:
1、 内部类可以直接访问外部类中的成员,包括私有成员
2、 外部类要访问内部类的成员,必须要建立内部类的对象
3、 在成员位置的内部类是成员内部类
4、 在局部位置的内部类是局部内部类

3.1成员内部类

//测试 内部类
public class Test1_Inner {
    public static void main(String[] args) {
        //创建内部类的对象的语法:外部类对象.内部类对象
        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()...");
        }
    }
}
被private修饰
package cn.tedu.inner;
//测试内部类被private修饰
public class Test5_InnerClass2 {
    public static void main(String[] args) {
//创建内部类对象,并执行show()
// Outer2.Inner2 oi = new Outer2().new Inner2();//报错,Inner2已经被private了
//3,测试被private的内部类的资源能否执行!
    new Outer2().test();
    }
}
class Outer2{
 //2,如果想要访问private的内部类,可以访问外部类提供的对应方法
    public void test() {
        //访问内部类方法
        new Inner2().show();
    }
//位置在类里方法外--成员内部类
//1,内部类可以被private修饰,但是外界无法直接创建对象了!
    private class Inner2{
        public void show() {
        System.out.println("Inner2.show()");
        }
    }
}
被static修饰
package cn.tedu.inner;
//测试内部类被static修饰
public class Test6_InnerClass3 {
    public static void main(String[] args) {
    // 创建内部类对象测试show()
    // Outer3.Inner3 oi = new Outer3().new Inner3();//报错,原因是Inner3是静态的内部类
        Outer3.Inner3 oi = new Outer3.Inner3();//Outer3.Inner3通过类名.调用类中的静态资源
        oi.show();
        Outer3.Inner3.show2();//调用静态内部类里的静态方法
    }
}
class Outer3{
    //1,内部类被static修饰--随着类的加载而加载,会造成内存资源浪费,并不常用!
    static class Inner3{
        public void show() {
        System.out.println("Inner3.show()");
        }
        static public void show2() {
            System.out.println("Inner3.show2()");
        }
    }
}

3.2 匿名内部类

//测试 匿名内部类
//总结:
//接口可以直接new对象,要配合匿名内部类使用(在内部类里重写了方法
public class Test2_Inner {
    public static void main(String[] args) {
        //优化方案:直接new接口,要配合匿名内部类使用(在内部类里重写了方法)--占内存少,不用实现类
        Inner in = new Inner() {
            @Override
            public void save() {
                System.out.println("数据保存成功");
            }
            @Override
            public void delete(int id) {
                System.out.println("数据删除成功,id是:"+id);
            }
        };
//        }.save();//调用指定方法
//    }.delete(5);//注意:调用指定方法--匿名对象一次只执行一个任务,只能2选1
        in.save();
        in.delete(10);
    }
}
interface Inner{
    //简写形式
    void save();
    void delete(int id);
}

4socket

4.1ServerSocket服务器端

创建对象:

    ServerSocket(int port) 
      创建绑定到特定端口的服务器套接字。

常用方法:

    Socket accept() 
      侦听并接受到此套接字的连接。 
    void close() 
      关闭此套接字。 

测试:

//socket通信的服务器端
public class Test1_Server {
    public static void main(String[] args) throws IOException {
        //1,开始服务器--端口号0~65535
        //在指定的8887端口号处,等待客户端的连接
        ServerSocket server = new ServerSocket(8887);
        System.out.println("服务器已开启。。。");
        
        //2,接收客户端连接请求,并建立通信通道Socket
        Socket accept = server.accept();
        System.out.println("接收一个客户端的请求。。");
        
        //3,读取客户端发来的数据
        InputStream in = accept.getInputStream();
        //读到的数据默认是int,转成字符类型
        for(int i = 0;i<5;i++) {
            char b = (char)in.read();
            System.out.print(b);
        }
        //4,服务器发送数据
        OutputStream out = accept.getOutputStream();
        String output = new Scanner(System.in).nextLine();
        out.write(output.getBytes());
        System.out.println("发送成功");
        //
        
    }

}

4.2socket客户端

创建对象:

Socket(String host, int port) 
          创建一个流套接字并将其连接到指定主机上的指定端口号。

常用方法:

InputStream getInputStream() 
          返回此套接字的输入流。 
        OutputStream getOutputStream() 
          返回此套接字的输出流。 

测试:

//socket通信的客户端
public class Test2_Client {
    static Socket socket =null;

    public static void main(String[] args) throws IOException {
        method2();//读取
        method();//写出
        
        //1,连接指定的服务器
        //本机ip--127.0.0.1
        //实际工作中,要写服务器的真是ip
        socket = new Socket("172.199.26.30",8888);
        System.out.println("客户端与服务器连接成功");
    }

    private static void method2() throws IOException {
        //3,读取服务器的数据
                InputStream in = socket.getInputStream();
                for(int i = 0;i<5;i++) {
                    char b = (char)in.read();
                    System.out.print(b);
                }
    }

    private static void method() throws IOException {
        //2,给服务器写出数据
                OutputStream out = socket.getOutputStream();
                System.out.println("请输入发给服务器的数据");
                String input = new Scanner(System.in).nextLine();
                out.write(input.getBytes());
                System.out.println("发送成功");
                out.flush();
    }

}

4.3BufferedReader

//服务器端
//读一行:BufferedReader()--readline()
//写一行:PrintWrite()--println()
public class Test3_BufferedReader {
    
    public static void main(String[] args) throws IOException {
        //1,开启服务器,开放端口
        ServerSocket server = new ServerSocket(8886);
        System.out.println("服务器已开启");
        //2,接收客户端请求,建立连接通道Socket
        Socket accept = server.accept();
        System.out.println("Sosket通道已建立");
//        rwmethod();//边读边写
        }

    public static void rwmethod() throws IOException {
        //1,创建读取对象
        BufferedReader br = new BufferedReader(new FileReader("./a.txt"));
        PrintWriter pw = new PrintWriter(new FileWriter("./b.txt"));
        String line ="";
        while((line = br.readLine())!=null) {//只要有数据,就一直读,没数据就返回null    
            pw.println(line);
        }
        br.close();
        pw.close();    
    }

/**
 * 用来写一行:PW
 * @param path 要把文档写在那个文件里去
 * @param date 写的内容
 * @throws IOException
 */
    public static void writeline(String path,String date) throws IOException {
        //1,创建对象
        PrintWriter pw = new PrintWriter(new FileWriter(path));
        //2,写出一行数据
        pw.println(date);
        //3,释放资源
        pw.close();
        
    }

/**
 * 用来读一行
 * @throws IOException
 */
    public static void readline(String path) throws IOException {
        //读一行:BufferedReader
        BufferedReader br = new BufferedReader(new FileReader(path));
        //读不到数据时,readline()返回null
//        String line = br.readLine();
        
        String line ="";//创建变量,记录读取到的一行数据
        while(line !=null) {//只要有数据,就一直读,没数据就返回null
            line = br.readLine();//一行一行读取数据
            System.out.println("line="+line);
        }
        br.close();
    }
}

4.4BufferedSocket

//客户端
public class Test3_BufferedSocket {
    public static void main(String[] args) throws IOException {
        //1,连接指定的服务器--输入服务器IP地址和端口号
        //本机ip--127.0.0.1
        Socket socket = new Socket("127.0.0.1",8886);
        System.out.println("客户端连接成功");
        Test3_BufferedReader.writeline("./b.txt","over");
        Test3_BufferedReader.readline("./a.txt");    
    }

}

5JDK新特性

JDK1.5-- 可变长参数(Varargs)method(int a,int...b)
JDK1.7--try--with--resources:自动关闭流
JDK1.8--Lambda表达式

使用Lambda语法来代替 匿名内部类,代码不仅简洁,而且还可读
语法:(参数列表) -> {方法体}
  --接口可以存在普通方法,但是需要用default/static修饰。

你可能感兴趣的:(java-se)