day24

发布时间:2024年01月24日

回顾

1.三种创建Class对象的形式
	Class.forName("")
	类.class
	对象.getCalss()
	字节文件.class对象
2.Class下面获取构造方法对象的方法
	getConstructors();
	getDeclaredConstructors();
	getConstructor(Class  ..... parameterType);
	getDeclaredConstructor(Class  ..... parameterType);
3.Class下面获取方法对象的方法
	getMethods();
	getDeclaredMethods();
	getMethod(String name, Class .... parameterType);
	getDeclaredMethod(String name, Class .... parameterType);
4.Class下面获取属性对象的方法
	getFields();
	getDeclaredFields();
	getField(String name);
	getDeclaredField(String name);
5.Constructor对象下面的方法
	newInstance(); 通过构造方法创建了实例对象
	setAccessible(true);
6.Method对象下面的方法
	setAccessible(true);
	invoke(Object  obj, Object ... param);
7.Field对象下面的方法
	setAccessible(true);
	set(Object obj, Object value);
8.简单聊聊对反射的理解

今天的内容

1.单例模式

2.序列化操作(IO流)

以下两个是jdk的新特性:

?

3.lambda表达式

4.Stream流

1.单例模式

Java提供了二十多种设计模式,在咱们教学过程中抽重要的学习,开发中用的

模式并不是一朝一夕学会的东西,工厂模式, 代理模式 策略模式等

设计模式是全球公认的。为了让咱们的代码变得更加简洁,效率更高,产生出来的模式

修改的时候更加方便

单例模式:

? 要求在整个程序运行过程中,只出现一个实例对象。减少内存的消耗

? 如何判断两个对象或者多个对象是否是单例,看内存地址。如果内存地址相等的话,绝对是同一个对象。

想一些问题:

? 创建对象 通过关键字 new 来创建,但是new一次 再new一次对象的内存地址绝对不一样的。就意味着你必须将一个类的构造方法私有化

package com.qfedu.f_singleinstance;

class SingDog {
    private static  SingDog singDog = null;
    private SingDog () {

    }
    public  static SingDog getInstance() {

        synchronized (SingDog.class) {
            if (singDog == null) {
                //
                singDog = new SingDog();
            }
        }
        return singDog;
    }


}
class MyThread1 implements Runnable {
    @Override
    public void run() {
        SingDog instance = SingDog.getInstance();
        System.out.println(instance);
    }
}
class MyThread2 implements Runnable {
    @Override
    public void run() {
        SingDog instance = SingDog.getInstance();
        System.out.println(instance);
    }
}

public class Demo1 {
    public static void main(String[] args) {

        //以上两个对象是两个不同的对象。单例模式的目的
        //是只能有一个对象,不能有多个对象,就意味着不能再new
        //为啥?new一个就是对象。不能new 在类里面咋写?
        //解决方案: 私有话构造方法
        //不能new  想得到对象? 在类中定义一个静态方法
        //为啥是静态方法  只能用来调用
//        SingDog singdog = SingDog.getInstance();
//
//        System.out.println(singdog);
//        SingDog singdog1 = SingDog.getInstance();
//        System.out.println(singdog1);
        new Thread(new MyThread1()).start();
        new Thread(new MyThread2()).start();

    }
}

懒汉式的写法

package com.qfedu.a_single;

//懒汉式写法
class Person {
    private static Person person;
    private Person () {

    }
    public static synchronized Person getInstance ()  {
        if  (person == null) {
            person = new Person();
        }
        return person;
    }
}

饿汉式写法

package com.qfedu.a_single;

class Cat {
    private static final Cat cat = new Cat();
    private Cat() {

    }
    public static Cat getIntance () {
        return cat;
    }
}
public class Demo3 {
    public static void main(String[] args) {
        Cat intance = Cat.getIntance();
        Cat intance1 = Cat.getIntance();
        System.out.println(intance);
        System.out.println(intance1);

    }

}

懒汉式:线程不安全

饿汉式:线程安全的

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

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

懒汉式的内存消耗是小于饿汉式的

2.序列化

和IO流有关

类 ObjectInputStream(反序列化) 和 ObjectOutputStream(序列化) 是高层次的数据流,它们包含反序列化和序列化对象的方法。

ObjectOutputStream 类包含很多写方法来写各种数据类型,但是一个特别的方法例外:

public final void writeObject(Object x) throws IOException

上面的方法序列化一个对象,并将它发送到输出流。相似的 ObjectInputStream 类包含如下反序列化一个对象的方法:

public final Object readObject() throws IOException, ClassNotFoundException

该方法从流中取出下一个对象,并将对象反序列化。它的返回值为Object,因此,你需要将它转换成合适的数据类型。

总结:序列化能干嘛? 将一个类对象信息(构造方法,属性,方法)可以写到本地一个文件中。这叫序列化。从文件中读取一个对象的信息,这叫反序列化。

序列化注意事项:

? 1.被序列化的实体类必须实现一个接口 Serializable,不然不能被序列化

序列化案例:

将一个对象赋值完以后写到到本地。ObjectOutputStream

package com.qfedu.b_serialize;

import java.io.*;
import java.util.ArrayList;

public class Demo1 {
    public static void main(String[] args) throws Exception {
        //序列化:将对象存到一个文件中
        Employee employee = new Employee();
        employee.name = "骚磊";
        employee.address = "月球";
        employee.number = 100;
        employee.mailCheck();
        //将employee对象进行序列化 存到一个文件中  序列化的文件的后缀都是.ser
        FileOutputStream fos = new FileOutputStream(new File("c:/aaa/emp.ser"));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fos);
        objectOutputStream.writeObject(employee);
        objectOutputStream.close();
        fos.close();
        System.out.println("写入成功");


    }
}

反序列化

将本地的文件信息(被序列化过的)写到一个对象中

ObjectInputStream

package com.qfedu.b_serialize;

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class Demo2 {
    public static void main(String[] args) throws Exception{
        //进行反序列化
        FileInputStream fis = new FileInputStream(new File("c:/aaa/emp1.ser"));
        ObjectInputStream ois = new ObjectInputStream(fis);
        Employee emp = (Employee)ois.readObject();
        System.out.println(emp.name);
        System.out.println(emp.number);
        System.out.println(emp.address);
        System.out.println(emp.sb);
        emp.mailCheck();

    }
}

总结:序列化将对象的值存到本地磁盘的文件中以作备份。反序列化可以将本次磁盘序列化过的文件读取到实体类的对象中。

3.Lambda表达式

Lambda表达式被称称为闭包。他是推动了Java8新特性的重要的一步。

Lambda表达式运行函数式编程。就是简化代码的。变得更加简洁,但是可读性特别差

3.1入门案例
package com.qfedu.c_lambda;

public class Demo1 {
    public static void main(String[] args) {
        //新建一个线程
        //第一种的创建方式
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("简洁嘻嘻哒" + i);
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("锤人" + i);
                }
            }
        }).start();

        //Thread构造方法是接口对象
        Runnable runnable = ()-> System.out.println("嘻嘻");
        new Thread(runnable).start();

    }
}

3.2lambda表达式语法格式

只看接口下面的唯一的一个抽象方法。

接口  接口对象 =  ()->表达式;  无参 无返回值的
接口  接口对象 =  (parameter)->表达式;  有参  无返回值的
接口  接口对象 = ()->{表达式;};   无参 有返回值的
接口  接口对象 = (parameter)->{表达式;};  有参有返回值
3.2.1无参无返回值的形式
package com.qfedu.c_lambda;

interface Computer {
    void coding();
}
public class Demo4 {
    public static void main(String[] args) {
        //无参无返回值的
        test(() -> System.out.println("敲代码"));
    }
    //而如果一个方法的参数是一个接口对象的话,难免要new 这个接口 重写方法
    
    public static void test (Computer c) {
        c.coding();
    }
}

3.2.2有参无返返回值的方法
package com.qfedu.c_lambda;

interface C {
    void eat(String name, int a);
}
public class Demo5 {
    public static void main(String[] args) {
        test(( name,  a) -> System.out.println(name + "吃" + a) , "狗蛋", 4);
    }
    public static void test (C c, String name, int a) {
        c.eat(name , a);
    }
}

3.2.3无参有返回值
package com.qfedu.c_lambda;

interface D {
    int num();
}
public class Demo6 {
    public static void main(String[] args) {
        test(() ->{
                if (true) {
                    System.out.println("xixida");
                }
                return 500;
            });
    }
    public static void test (D d) {
        d.num();
    }
}

3.2.4有参有返回值的
package com.qfedu.c_lambda;

interface E {
    int add(int a, int b);
}
public class Demo7 {
    public static void main(String[] args) {
        test((a, b) -> a + b, 2, 3);

    }
    public static void test (E e, int a, int b) {
        int sum = e.add(a, b);
        System.out.println(sum);
    }
}

今天的内容

1.反射【重点】

1.反射

反射很重要,咱们以后进行封装的时候都有必要书写反射,让咱们的代码具有更强普适性

Java反射是在动态的获取类, 类属性, 类方法, 类构造方法等内部一些类的信息。

反射本质就是反着来。

平常获取类 new 一个对象,现在可以通过反射来获取。

package com.qfedu.a_reflect;

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

public class Demo1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //想创建一个对象,直接new
        Person person = new Person();
        //今天再学一种方式 使用反射的方式获取一个类的对象
        //java执行原理:先编译 后执行
        //编译之后的文件叫 Person.class  编
        // 译之后所有东西(类的属性,类的构造方法,类的成年成员方法)
        //都在person.class文件中,这个文件变成了一个类对象了
        //personClasss里卖弄有类的所有的信息
        Class<Person> personClass = Person.class;
        //getConstructor获得无参构造方法
        //Constructor  把无参构造方法封装给以一个对象
        Constructor<Person> constructor = personClass.getConstructor(null);
        //要无参构造干嘛?可以通过构造方法创建对象!!!
        Person person1 = constructor.newInstance(null);


    }
    public static void test(Person p) {

    }
    public static void test(Class cls) {
        
    }
}

从数据库里面查数据,但是查出来的数据要赋值一个类
new admin ();
new goods();
new order();
三个类对应这数据库里面这三张表
admin表:
	name   pwd
	狗蛋	  123
goods表:
	name   price
	汽车    78.9
order:
	name   status
	汽车    已付款
class BasweDao {
public List<T>  query (Class cls) {
	获取了name pwd  price   status
	值已经获取出来
	//得把这些值赋值给实体类
	//Admin admin = new Admin();
	//只能对admin赋值了,其他类不能赋值,这就不叫封装了,封装的目的是具有普适性
	Constructor<T> cst = cls.getConstructor(null);
	T t = cst.newInstance(null);
	
}
}
Admin.class
query(Admin.class);
query(Goods.class);
query(Order.class);
1.1获取Class对象

为啥要获取Class对象?因为有了class对象才能找关于类的属性,方法 , 构造方法

Java可以将.java文件编译成.class文件,这个.calss文件中包含了原始文件中的所有的信息

.class文件会被类加载器加载到虚拟机中,可以通过.class文件获取原始类中的所有的信息

随之产生一个Class类对象。将Person.class变成了一个Class对象了

获取一个类的Class对象有三种方式:

package com.qfedu.b_class;

import com.qfedu.a_reflect.Person;

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种获取class对象方式
        //com.qfedu.a_reflect.Person 类全限定名
        Class<?> aClass = Class.forName("com.qfedu.a_reflect.Person");
        System.out.println(aClass);
        //第二种方式
        Class<Person> personClass = Person.class;
        System.out.println(personClass);
        //第三种方式
        Class<? extends Person> aClass1 = new Person().getClass();
        System.out.println(aClass1);

    }
}

为啥要获取一个类的字节码文件对象,因为我要获取字节码文件下面的 构造方法 方法 属性 等信息

1.2获取Constructor对象

和一个类中的构造方法有关系。构造方法类对象

Constructor<?>[]getConstructors()返回包含一个数组 Constructor对象反射由此表示Class的所有公共构造 方法对象。
Constructor<?>[]getDeclaredConstructors()返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组
Constructor<T>getConstructor(Class<?>... parameterTypes)返回一个 Constructor对象,该对象反映 Constructor对象表示的类
Constructor<T>getDeclaredConstructor(类<?>... parameterTypes)返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 构造方法对象

以上的方法都是Class对象调用的

下面这个方法是Construct对象调用的

TnewInstance(Object... initargs)使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
package com.qfedu.c_constructor;

import com.qfedu.a_reflect.Person;

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

public class Demo1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取一个类对应的class对象
        Class<Person> personClass = Person.class;
        //2.再拿class对象获取构造方法对象
        Constructor<?>[] constructors = personClass.getConstructors();
        System.out.println(constructors);//内存地址
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);

        }
        System.out.println("-========");
        //3.获取一个类所有的构造方法对象
        Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        //4.获取单个的constructor对象
        //参数是个null  就证明获取的是无参的
        Constructor<Person> constructor = personClass.getConstructor(null);
        System.out.println(constructor);//Person();
        System.out.println("----------");
        //5获取带有字符串类型的有参构造方法
        //参数Class 对象 怎么将String转为Class对象
        Constructor<Person> constructor1 = personClass.getConstructor(String.class);
        System.out.println(constructor1);//Person(String name)
        Constructor<Person> constructor2 = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor2);//Person(String name)
        //不能的!!!
//        Constructor<Person> constructor3 = personClass.getConstructor(int.class);
//        System.out.println(constructor3);//Person(int name)
        //6.获取私有化的构造方法
        Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(int.class);
        System.out.println(declaredConstructor);

        //newInstance(Object... parameter)  是Constructor对象调用的
        //不是calss对象调用的  通过构造方法对象实例化一个对象出来
        Person person = constructor.newInstance(null);
        System.out.println(person);
        //如果有参的构造方法 有参构造方法可以传值
        Person person1 = constructor1.newInstance("狗蛋");
        System.out.println(person1);
        Person person2 = constructor2.newInstance("老邢", 18);
        System.out.println(person2);
    }
}

只用getConstructor(Class…parameterType);

newInstance(Object… initargs);

一个类下面有构造方法 方法 属性

1.3获取Method对象
Method[]getMethods()获取当前类或者父类的公开的所有的方法
Method[]getDeclaredMethods()获取当前类所有的方法,但是不能获取父类的方案
MethodgetMethod(String name, 类<?>... parameterTypes)返回一个 方法对象,它反映此表示的类或接口的指定公共成
MethodgetDeclaredMethod(String name, 类<?>... parameterTypes)返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 对象。

学一个Method下面的方法

Objectinvoke(Object obj, Object… args)在具有指定参数的 方法对象上调用此 方法对象
package com.qfedu.d_method;

import com.qfedu.a_reflect.Person;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo1 {
    public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<Person> personClass = Person.class;
        //通过class对象获取一个类下面方法对象Method
        //打印的本类公开的方法和父类的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("==========");
        //获取本类的所有的方法
        Method[] declaredMethods = personClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {

            System.out.println(declaredMethod);
        }
        //获取一个方法  第一个参数  String方法的名字,第二个参数 方法的参数的数据类型
        Method eat = personClass.getMethod("eat", null);
        System.out.println(eat);//无参的eat方法
        Method eat1 = personClass.getMethod("eat", String.class);
        System.out.println(eat1);//有参的eat方法 参数string类型的数据

        //私有话的方法getDeclaredMethod
        Method sleep = personClass.getDeclaredMethod("sleep", null);
        System.out.println(sleep);
        //方法对象获取以后干嘛?
        //方法要被调用  使用Method对象调用invoke这个方法
        //第一个Object 是你得告诉我在那个对象下面调用

        //Object... args  是方法的参数的实参!!!
        //invoke(Object obj, Object... args)在具有指定参数的 `方法`对象上调用此 `方法`对象
        Person person = personClass.newInstance();
        //方法对象自己执行方法
        eat.invoke(person, null);
        eat1.invoke(person, "狗子");

        //证明权限不够!!!咋办 接近不了
        //can not access a member
        //咋办,让它接近就可以啦。 暴力反射
        sleep.setAccessible(true);
        sleep.invoke(person, null);
    }
}

总结:

getMethod(string name, class<?> ... parameterType);
调用
invoke(Object obj, Object....paramter)

上午的内容

1.获取三种方式
	Class.forName("包名+ 类名");
	类.class
	对象.getClass()
2.获取构造方法对象
	class对象.getConstructor();
	construct对象.newInstance();根据构造方法实例化对象
3.获取方法对象
	class对象.getMethod(String name, Class<?> ...parameterType);
	method对象.invoke(Object obj, Object... initargs);

类下面还有成员变量

Field

1.4获取Field对象
package com.qfedu.e_field;

import com.qfedu.a_reflect.Person;

import java.lang.reflect.Field;

public class Demo1 {
    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        //属性是在一个类下面,也要Class对象获取属性对象
        Class<Person> personClass = Person.class;
        //getFields获取公开的属性
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("===========");
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {

            System.out.println(declaredField);
        }
        //获取一个属性对象 参数是属性的名字
        Field name = personClass.getField("name");
        System.out.println(name);
        //能不能使用getField方法获取私有的属性或者默认的属性?不能!!
//        Field age = personClass.getField("age");
//        System.out.println(age);
        Field age = personClass.getDeclaredField("age");
        System.out.println(age);
        Field sex = personClass.getDeclaredField("sex");
        System.out.println(sex);
        //属性对象可以获取的,获取以后干嘛?属性是用来赋值的
        //对象属性进行赋值  set方法
        Person person = personClass.newInstance();
        name.set(person, "狗子");
        System.out.println(person);
        //暴力反射
        age.setAccessible(true);
        age.set(person, 12);
        System.out.println(person);

    }
}

今天的作业:

1.整理一下笔记
2.必须要弄懂反射下面的方法 大概15个方法
3.今天一定要消化
	找一些博客看看
文章来源:https://blog.csdn.net/qq_57747969/article/details/135826024
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。