812笔记---小白学Java

反射

反射是Java中的一种机制,可以通过Java代码对一个类进行解析;例如获取类的属性、方法、构造方法等。

获取Class对象相关方法

  • public T newInstance() :创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法

示例

Student类

package com.qfedu.demo;

/**
 * @Author pengyu
 * @Date 2022/8/12 18:34
 */
public class Student {
    private String name;
    public int id;
    //如果在这里加上transient便不会进行序列化,我就不演示了
    //transient char sex;
    char sex;

    public Student() {
    }

    public Student(String name, int id, char sex) {
        this.name = name;
        this.id = id;
        this.sex = sex;
    }
    
    private Student(String name) {
        this.name = name;
    }

    private Student(int id) {
        this.id = id;
    }

    public void say () {
        System.out.println("我会说话!!!");
    }
    
    public void print(String name) {
        System.out.println(name + "写作业!");
    }
    
    private void sleep () {
        System.out.println("小宝宝,该睡觉了哦!");
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", sex=" + sex +
                '}';
    }
}

测试

package com.qfedu.demo;

import java.lang.reflect.Constructor;

/**
 * @Author pengyu
 * @Date 2022/8/12 18:51
 */
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 三种获得Student的Class的对象
        Class<Student> studentClass = Student.class;
        System.out.println(studentClass);

        //("com.qfedu.demo.Student")全限定性类名
        Class<?> aClass = Class.forName("com.qfedu.demo.Student");
        System.out.println(aClass);

        Student student = new Student();
        Class<? extends Student> aClass1 = student.getClass();
        System.out.println(aClass1);

        /**
         * 控制台打印结果:
         * class com.qfedu.demo.Student
         * class com.qfedu.demo.Student
         * class com.qfedu.demo.Student
         */
    }
}

Class中获取Constructor(构造方法)对象相关方法

相关方法

  • public Constructor getConstructor(Class... parameterTypes) :根据参数类型获取构造方法对象,只能获得public修饰的构造方法。如果不存在对应的构造方法,则会抛出java.lang.NoSuchMethodException 异常。
  • Constructor getDeclaredConstructor(Class... parameterTypes):根据参数类型获取构造方法对象**,能获取所有的构造方法(public、默认、protected、private )**。如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
  • Constructor[] getConstructors(): 获取所有的public修饰的构造方法
  • Constructor[] getDeclaredConstructors():获取所有构造方法,包括public、默认、protected、private
  • T newInstance(Object... initargs): 根据指定参数创建对象。
  • void setAccessible(true):开启强制访问,除public修饰的构造方法外,其他构造方法反射都需要暴力反射

示例

package com.qfedu.demo;

import java.lang.reflect.Constructor;

/**
 * @Author pengyu
 * @Date 2022/8/12 18:58
 */
public class Demo03 {
    public static void main(String[] args) throws NoSuchMethodException {
        //获取Class对象
        Class<Student> studentClass = Student.class;
        //获取public修饰的所有构造方法,在一个数组中
        Constructor<?>[] constructors = studentClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        /**
         * 控制台打印结果:
         * public com.qfedu.demo.Student(java.lang.String,int,char)
         * public com.qfedu.demo.Student()
         */

        //获取Student类中的所有构造方法
        Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        /**
         * 控制台打印结果:
         * private com.qfedu.demo.Student(int)
         * private com.qfedu.demo.Student(java.lang.String)
         * public com.qfedu.demo.Student(java.lang.String,int,char)
         * public com.qfedu.demo.Student()
         */

        //获取public修饰的无参构造方法,null即为无参
        Constructor<Student> constructor = studentClass.getConstructor(null);
        System.out.println(constructor);
        /**
         * 控制台打印结果:
         * public com.qfedu.demo.Student()
         */

        //获取指定的构造方法,也就是说我们要获取有参的构造方法,只需在()里面添加相应的Class,多个用','隔开
        Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class);
        System.out.println(declaredConstructor);
        /**
         * 控制台打印结果:
         * private com.qfedu.demo.Student(int)
         */
    }
}

Class中获取类中的Method(方法)相关方法

这个跟构造方法的意思一样

相关方法

  • public Method getMethod(String name, Class<?>... parameterTypes):根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
  • public Method getDeclaredMethod(String name, Class<?>... parameterTypes):根据方法名和参数类型获得一个方法对象,包含任意修饰符的
  • public Method[] getMethods():获取所有的public修饰的成员方法,包括父类中的方法。
  • public Method[] getDeclaredMethods():获取当前类中所有的方法,包含任意修饰符的,但不包括父类中。

常用方法

  • public Object invoke(Object obj, Object... args) :根据参数args调用对象obj的该成员方法,如果obj=null,则表示该方法是静态方法
  • public void setAccessible(boolean flag) :开启强制访问,设置为可以直接调用非public修饰的方法
  • public String getName():获取此对象封装的方法名

示例

package com.qfedu.demo;

import java.lang.reflect.Method;

/**
 * @Author pengyu
 * @Date 2022/8/12 19:15
 */
public class Demo04 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Student> studentClass = Student.class;
        //获取所有public修饰的方法,包括父类中的
        Method[] methods = studentClass.getMethods();
//        for (Method method : methods) {
//            System.out.println(method);
//        }

        //获取Student类中的所有方法
        Method[] declaredMethods = studentClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        /**
         * 控制台打印结果:
         * public void com.qfedu.demo.Student.say()
         * public java.lang.String com.qfedu.demo.Student.toString()
         * private void com.qfedu.demo.Student.sleep()
         * public void com.qfedu.demo.Student.print(java.lang.String)
         */

        //获取指定的方法,public修饰的,无参
        Method say = studentClass.getMethod("say");
        System.out.println(say);
        /**
         *  控制台打印结果:
         *  public void com.qfedu.demo.Student.say()
         */

        //获取指定的方法,public修饰的,有参,可以传String类型的参数
        Method print = studentClass.getMethod("print", String.class);
        System.out.println(print);
        /**
         * 控制台打印结果:
         * public void com.qfedu.demo.Student.print(java.lang.String)
         */

        //获取指定的方法,可以是非public修饰的
        Method sleep = studentClass.getDeclaredMethod("sleep");
        System.out.println(sleep);
        /**
         * 控制台打印结果:
         * private void com.qfedu.demo.Student.sleep()
         */
        
        /**
         *  方法的调用
         *  1.要有对象
         *  2.自己执行方法
         */
        Student student = studentClass.newInstance();
        print.invoke(student, "依依");
        //控制台打印结果:依依写作业!
    }
}

Class中获取Field(属性)相关方法

相关方法

  • Field getDeclaredField(String name):根据属性名获得属性对象,包括private修饰的
  • Field getField(String name) :根据属性名获得属性对象,只能获取public修饰的
  • Field[] getFields():获取所有的public修饰的属性对象,返回数组。
  • Field[] getDeclaredFields():获取所有的属性对象,包括private修饰的,返回数组。

常用方法

  • void set(Object obj, Object value):给指定的属性设置值
  • Object get(Object obj) :获取属性字段的值
  • void setAccessible(boolean flag):开启强制访问
  • Class getType():获取属性的类型,返回Class对象。

示例

package com.qfedu.demo;

import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MatchGenerator;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author pengyu
 * @Date 2022/8/12 18:35
 */
public class Test01 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //反射第一步:使用类来创建Class对象
        Class<Student> studentClass = Student.class;
        //第二步:获取无参构造方法
        Constructor<Student> constructor = studentClass.getConstructor(null);
        //第三步:通过无参构造创建对象
        Student student = constructor.newInstance();
        //我们如何赋值呢?
        Field name = studentClass.getDeclaredField("name");
        Field id = studentClass.getField("id");
        Field sex = studentClass.getDeclaredField("sex");

        //暴力反射,开启强制访问,因为name属性是private所修饰的,只要不是public修饰都需要暴力
        name.setAccessible(true);
        name.set(student, "卡哇伊");
        id.set(student, 001);
        sex.setAccessible(true);
        sex.set(student, '女');
        System.out.println(student);

        //控制台输出打印结果:Student{name='卡哇伊', id=1, sex=女}

        // 获取属性字段的值
        Object o = name.get(student);
        System.out.println(o);
        //控制台输出打印结果:卡哇伊
    }
}

序列化和反序列化

序列化:指把Java对象转换为字节序列的过程。

反序列化:指把字节序列恢复为Java对象的过程。

要求

  1. 只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)
  2. 使用对应的API
    1. java.io.ObjectInputStream:对象输入流。 该类的readObject()方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。
    2. java.io.ObjectOutputStream:对象输出流。该类的writeObject(Object obj)方法将将传入的obj对象进行序列化,把得到的字节序列写入到目标输出流中进行输出。

示例:序列化

package com.qfedu.demo;

import com.sun.xml.internal.ws.api.pipe.ServerTubeAssemblerContext;

import java.io.*;

/**
 * @Author pengyu
 * @Date 2022/8/12 19:35
 */
public class Demo07 {
    public static void main(String[] args) throws IOException {

        //序列化,这时我电脑路径中是没有这个文件的,它会自动生成
        Student student = new Student("小哈", 001, '男');
        FileOutputStream fos = new FileOutputStream(new File("D:/aaa/888.ser"));
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(student);

        oos.close();
        fos.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3wsJRwQh-1660309246687)(1.jpg)]

示例:反序列化

package com.qfedu.demo;

import java.io.*;

/**
 * @Author pengyu
 * @Date 2022/8/12 19:46
 */
public class Demo06 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //反序列化
        FileInputStream fis = new FileInputStream(new File("D:/aaa/888.ser"));
        ObjectInputStream ois = new ObjectInputStream(fis);
        //强转
        Student o = (Student)ois.readObject();
        System.out.println(o);
        //打印:Student{name='小哈', id=1, sex=男}

    }
}

单例模式

单例模式有以下特点:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

懒汉式单例

package com.qfedu.demo;

/**
 * @Author pengyu
 * @Date 2022/8/12 19:54
 */
class A {
    private static A a = null;
    private A() {
    }
    public static A getA() {
        if (a == null) {
            a = new A();
        }
        return a;
    }
}
public class Demo05 {
    public static void main(String[] args) {
        A a = A.getA();
        A a1 = A.getA();
        System.out.println(a);  //com.qfedu.demo.A@154617c
        
        System.out.println(a1);  //com.qfedu.demo.A@154617c

        System.out.println(a == a1);  //true
    }
}

饿汉式单例

class B {
    private B() {}
    private static final B b = new B();

    public static B getInstance() {
        return b;
    }

}

1、线程安全:

饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题。

懒汉式本身是非线程安全的。

2、资源加载和性能:

饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,

而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

  • 效率来说: 饿汉式效率高,因为不用加锁

  • 性能来说: 饿汉式类一加载就实力出来对象。但是懒汉式调用方法的时候才进行创建对象,懒汉式的内存消耗是小于饿汉式的

JDK1.8新特性

  • Lambda表达式
  • 函数式接口
  • *方法引用和构造器调用
  • Stream API
  • **接口中的默认方法和静态方法 **:可以看我之前726笔记,接口知识点
  • 新时间日期API

Lambda表达式

Lambda主要是简化了匿名内部类的写法,并且Lambda表达式只能简化函数式接口的写法;也就是说,要使用Lambda表达式必须保证接口中只有一个抽象方法

初体验

接口

package com.qfedu.lambda;

/**
 * @Author pengyu
 * @Date 2022/8/12 20:39
 */
public interface Task {
    void run();
}

实体类

package com.qfedu.lambda;

/**
 * @Author pengyu
 * @Date 2022/8/12 20:39
 */
public class Person {
    private Task task;

    public void run() {
        if (task != null) {
            task.run();
        }
    }

    public Person() {
    }

    public Person(Task task) {
        this.task = task;
    }

    public Task getTask() {
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }
}

测试

package com.qfedu.lambda;

/**
 * @Author pengyu
 * @Date 2022/8/12 20:41
 */
public class Demo01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setTask(new Task() {
            @Override
            public void run() {
                System.out.println("跑起来了1!!!");
            }
        });
        person.run();

        Person person1 = new Person();
        person1.setTask(
                () -> {
                    System.out.println("跑起来了2!!!");
                }
        );
        person1.run();

    }
}

Lambda表达式的语法:

() -> {
System.out.println(“跑起来了2!!!”);
}

  1. 前面的一对小括号代表要实现的那个方法(Task接口的run方法)的参数列表。
  2. 中间的箭头是固定语法,用于分隔参数列表和方法体。
  3. 大括号里面就是实现的具体业务逻辑代码;当方法体中只有一句代码时,大括号可以省略。
接口  接口对象 =  ()->表达式;  无参 无返回值的
接口  接口对象 =  (parameter)->表达式;  有参  无返回值的
接口  接口对象 = ()->{表达式; return 返回值};   无参 有返回值的
接口  接口对象 = (parameter)->{表达式; return 返回值};  有参有返回值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值