黑马程序员--Java学习日记之类的加载,反射,动态代理,枚举

本文深入探讨Java反射机制及其在类加载、构造方法、成员变量与方法获取、数组反射、配置文件读取、泛型应用以及动态代理等方面的应用。通过实例演示,展示反射在增强代码灵活性和复用性方面的强大能力。

 

                                            ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


一、类的加载

1、类的加载相关概述

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三步来对这个类进行初始化。

①加载

  • 就是指将class文件读入内存,并为之创建一个Class对象
  • 任何类被使用时系统都会建立一个Class对象。

②连接

  • 验证 是否有正确的内部结构,并和其他类协调一致
  • 准备 负责为类的静态成员分配内存,并设置默认初始化值
  • 解析 将类的二进制数据中的符号引用替换为直接引用
③初始化:跟以前的初始化动作一样。

2、类加载器

①概念:负责将.class文件加载到内存中,并为之生成对应的Class对象。

②类加载器的组成:

  • Bootstrap Classloader根类加载器。也称为引导类加载器负责java核心类的加载,比如System.String等。在JDK中JRE的lib目录下rt.jar文件中。
  • Extension ClassLoader扩展类加载器。负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下的ext目录。
  • System CkassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及负责classpath环境变量所指定的jar包和路径。主要是用来加载我们写的文件。

二、反射

1、反射的基石——Class类

①所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

  • Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。
  • 而field中有修饰符、类型、变量名等复杂的描述内容,因此也可以将字段封装称为一个对象。用来获取类中field的内容,这个对象的描述叫Field。同理方法和构造函数也被封装成对象Method、Constructor。要想对一个类进行内容的获取,必须要先获取该字节码文件的对象。该对象是Class类型。
  • Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;

②Class和class的区别

  • class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
  • Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。

2、反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简而言之,反射就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用就是Class类中方法

获取Class文件对象的方式:

①Object类的getClass()方法。获取字节码文件对象。

Personp = new Person();

Classc = p.getClass();

②数据类型的静态属性class:比第一种方式简单,不用创建对象,也不会调用getClass方法,但是还是要使用具体的类对象和该类的一个静态属性完成。

Classc2 = Person.class;

③Class类中的静态方法forName()方法。注意:要拿带包名的全路径名称:这种方式比较简单,不用创建对象,也不用调用方法,也不需要去调用具体的属性和行为,就能获取到Class对象了。

Classc3 = Class.forName("Person");

一般我们到底使用哪种方法呢?

自己玩:任选一种,第二种较为方便

开发:第三种。为什么呢?因为第三种是一个字符串,而不是一个具体的类名,这样我们就可以把这样的字符串配置到配置文件中。

三种获取Class文件对象的方式演示:



package cn.itcast_01;  
02.  
03./* 
04. *获取Class文件对象的三种方式 
05. */  
06.public class ReflectDemo {  
07.    public static void main(String[] args) throws ClassNotFoundException {  
08.        //第一种  
09.        Person p = new Person();  
10.        Class c = p.getClass();  
11.  
12.        Person p2 = new Person();  
13.        Class c2 = p2.getClass();  
14.  
15.        System.out.println(p == p2);// false  
16.        System.out.println(c == c2);// true  
17.  
18.        //第二种  
19.        Class c3 = Person.class;  
20.        // int.class;  
21.        // String.class;  
22.        System.out.println(c == c3);  
23.  
24.        // 第三种  
25.        // ClassNotFoundException  
26.        Class c4 = Class.forName("cn.itcast_01.Person");  
27.        System.out.println(c == c4);  
28.    }  
29.}  

3、Class类中的常用方法

通过反射获取和使用构造方法和类中成员变量即成员方法

①获取构造方法

  • getConstructor(Class<?>... parameterTypes):返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
  • getDeclaredConstructor(Class<?>... parameterTypes):返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。

②创建对象

  • newInstance():创建此 Class 对象所表示的类的一个新实例。

③获取所有成员

  • getFields():返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
  • getDeclaredFields():返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

④获取单个成员

  • getField(String name):返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
  • getDeclaredField(String name):返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

⑤获取所有方法

  • getMethods():返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
  • getDeclaredMethods(): 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

⑥获取单个方法

  • getMethod(String name,Class<?>... parameterTypes): 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
  • getDeclaredMethod(String name,Class<?>... parameterTypes): 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

方法演示代码如下:


package cn.itcast_02;  
02.  
03.import java.lang.reflect.Constructor;  
04.  
05.import cn.itcast_01.Person;  
06.  
07./* 
08. * 通过反射获取构造方法并使用。 
09. */  
10.public class ReflectDemo {  
11.    public static void main(String[] args) throws Exception {  
12.        // 获取字节码文件对象  
13.        Class<?> c = Class.forName("cn.itcast_01.Person");  
14.  
15.        // 获取构造方法  
16.        // public Constructor[] getConstructors():所有公共构造方法  
17.        // public Constructor[] getDeclaredConstructors():所有构造方法  
18.        Constructor<?> [] cons = c.getDeclaredConstructors();  
19.        for (Constructor<?> con : cons) {  
20.            System.out.println(con);  
21.        }  
22.  
23.        // 获取单个构造方法  
24.        // public Constructor<T> getConstructor(Class<?>... parameterTypes)  
25.        // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象  
26.        Constructor<?> con = c.getConstructor();// 返回的是构造方法对象  
27.  
28.        Person p = new Person();  
29.        System.out.println(p);  
30.        // public T newInstance(Object... initargs)  
31.        // 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,  
32.        //并用指定的初始化参数初始化该实例。  
33.        Object obj = con.newInstance();  
34.        System.out.println(obj);  
35.  
36.        Person p1 = (Person) obj;  
37.        p1.show();  
38.    }  
39.}  

4、Constructor<T>类

①概述:当指定的类中没有空参数构造函数时,或者创建的类对象需要通过指定的构造函数进行初始化,这时候就不能使用Class类中的newInstance方法。这时候我们就需要通过其它的方法来实现了。
②Constructor代表的是某个类的一个构造方法。提供关于类的单个构造方法的信息以及对它的访问权限。
③获取构造方法

  • 获取所有的构造方法:Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
  • 获取单个构造方法:Constructor con=Person.class.getConstructor(String.class,int.class);

④创建实例对象

  • 反射方式:Person p= (Person)con.newInstance(“lisi”,30);
  • 通常方式:Person p = new Person(“lisi”,30);

注意:创建实例时newInstance方法中的参数列表必须与获取Constructor的方法getConstructor方法中的参数列表一致。

5、Field类

①Field代表的是某个类的某个成员变量。
②方法:

  • Field getField(String s);只能获取公有和父类中公有
  • Field getDeclaredField(String s);获取该类中任意成员变量,包括私有
  • setAccessible(ture);如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。
  • set(Object obj, Object value);将指定对象变量上此Field对象表示的字段设置为指定的新值。
  • Object get(Object obj);返回指定对象上Field表示的字段的值。



代码演示如下:

package cn.itcast_03;  
02.  
03.import java.lang.reflect.Constructor;  
04.import java.lang.reflect.Field;  
05.  
06./* 
07. * 通过发生获取成员变量并使用 
08. */  
09.public class ReflectDemo {  
10.    public static void main(String[] args) throws Exception {  
11.        // 获取字节码文件对象  
12.        Class<?> c = Class.forName("cn.itcast_01.Person");  
13.  
14.        // 获取所有的成员变量  
15.        // Field[] fields = c.getFields();  
16.        // Field[] fields = c.getDeclaredFields();  
17.        // for (Field field : fields) {  
18.        // System.out.println(field);  
19.        // }  
20.  
21.        /* 
22.         * Person p = new Person(); p.address = "北京"; System.out.println(p); 
23.         */  
24.  
25.        // 通过无参构造方法创建对象  
26.        Constructor<?> con = c.getConstructor();  
27.        Object obj = con.newInstance();  
28.        System.out.println(obj);  
29.  
30.        // 获取单个的成员变量  
31.        // 获取address并对其赋值  
32.        Field addressField = c.getField("address");  
33.        // public void set(Object obj,Object value)  
34.        // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。  
35.        addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"  
36.        System.out.println(obj);  
37.  
38.        // 获取name并对其赋值  
39.        // NoSuchFieldException  
40.        Field nameField = c.getDeclaredField("name");  
41.        // IllegalAccessException  
42.        nameField.setAccessible(true);  
43.        nameField.set(obj, "林青霞");  
44.        System.out.println(obj);  
45.  
46.        // 获取age并对其赋值  
47.        Field ageField = c.getDeclaredField("age");  
48.        ageField.setAccessible(true);  
49.        ageField.set(obj, 27);  
50.        System.out.println(obj);  
51.    }  
52.}  

6、Method类

①概述:Method类代表类中的一个成员方法,调用某个对象身上的方法,要先得到方法,再针对某个对象调用。
②举一个例子:获得String类的charAt方法。
Method methodCharAt=Class.forName("java.lang.String").getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str,1));//调用str对象中charAt(1)
③调用方法

  • 通常方式:System.out.println(str.charAt(1));
  • 反射方式:System.out.println(charAt.invoke(str,1));//str是一个对象,这里str可以是null,说明invoke()方法是一个静态方法。

④实例应用:用反射方式执行某个类中的main方法
a、目的:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的Main方法。
b、问题:启动java程序的main方法的参数是一个字符串数组, 即public static void main(String[]args),通过反射方式来调用这个main方法时,按jdk1.5的语法,整个数组是一个参数,而jdk1.4的语法,数组的每个元素对应一个参数,当做把一个字符串数组作为参数传递给invoke方法如何处理(注意兼容)。所以,在给main方法传递参数时,不能使用代码mainMthod.invoke(null,newString[]{“xxxx”}),javac只把它当做JDK1.4的语法进行理解,。而不能把它当做JDK1.5的语法解释,因此,会出现参数类型不对的问题。
c、解决办法:

  • 方法一:mainMethod.invoke(null,newObject[]{new String[]{xxxx}});
  • 方法二:mainMethod.invoke)((Object)newString[]{"xxxx"});编译器会做特殊处理,编译时不把参数当做数组看待,也就不会数组达三成若干参数

实例一:Method方法演示


package cn.itcast_04;  
02.  
03.import java.lang.reflect.Constructor;  
04.import java.lang.reflect.Method;  
05.  
06.public class ReflectDemo {  
07.    public static void main(String[] args) throws Exception {  
08.        // 获取字节码文件对象  
09.        Class<?> c = Class.forName("cn.itcast_01.Person");  
10.  
11.        // 获取所有的方法  
12.        // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法  
13.        // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法  
14.        // for (Method method : methods) {  
15.        // System.out.println(method);  
16.        // }  
17.  
18.        Constructor<?> con = c.getConstructor();  
19.        Object obj = con.newInstance();  
20.  
21.        /* 
22.         * Person p = new Person(); p.show(); 
23.         */  
24.  
25.        // 获取单个方法并使用  
26.        // public void show()  
27.        // public Method getMethod(String name,Class<?>... parameterTypes)  
28.        // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型  
29.        Method m1 = c.getMethod("show");  
30.        // obj.m1(); // 错误  
31.        // public Object invoke(Object obj,Object... args)  
32.        // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数  
33.        m1.invoke(obj); // 调用obj对象的m1方法  
34.  
35.        System.out.println("----------");  
36.        // public void method(String s)  
37.        Method m2 = c.getMethod("method", String.class);  
38.        m2.invoke(obj, "hello");  
39.        System.out.println("----------");  
40.  
41.        // public String getString(String s, int i)  
42.        Method m3 = c.getMethod("getString", String.class, int.class);  
43.        Object objString = m3.invoke(obj, "hello", 100);  
44.        System.out.println(objString);  
45.        // String s = (String)m3.invoke(obj, "hello",100);  
46.        // System.out.println(s);  
47.        System.out.println("----------");  
48.  
49.        // private void function()  
50.        Method m4 = c.getDeclaredMethod("function");  
51.        m4.setAccessible(true);  
52.        m4.invoke(obj);  
53.    }  
54.}  

实例二: 写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。

package cn.itheima;  
02.//定义一个测试类  
03.class Test{  
04.    public static void main(String[] args){  
05.        for(String arg : args){  
06.            System.out.println(arg);  
07.        }  
08.    }  
09.}  
10.//用反射方式根据用户提供的类名,去执行该类中的main方法。  
11.import java.lang.reflect.Method;  
12.  
13.public class PerformedMain{  
14.  
15.    public static void main(String[] args) throws Exception {  
16.        //普通方式  
17.        Test.main(new String[]{"123","456","789"});  
18.        System.out.println("-----------------------------");  
19.                  
20.        //反射方式  
21.        String className=args[0];  
22.        Class clazz=Class.forName(className);  
23.                  
24.        Method methodMain=clazz.getMethod("main",String[].class);  
25.        //方式一:强制转换为超类Object,不用拆包  
26.        methodMain.invoke(null, (Object)new String[]{"123","456","789"});  
27.        //方式二:将数组打包,编译器拆包后就是一个String[]类型的整体   
28.        methodMain.invoke(null, new Object[]{new String[]{"123","456","789"}});  
29.    }  

三、数组的反射

①具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
②代表数组的Class实例对象的getSuperClass()方法,返回的父类为Object类对应的Class
③基本类型的一维数组可以被当做Object类型使用,不能作为Object[]类型使用,不能当做Object[]类型使用,非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类使用
④ 注意区别 Array.asList()方法处理int[]和String[]时的差异
⑤ Array工具类用于完成对数组的反射操作

  • Array.getLength(Object obj);获取数组的长度
  •  Array.get(Object obj,int x);获取数组中的元素

     四.反射的重要应用

1.通过反射运行配置文件的内容


public class Demo {  
02.    public static void main(String[] args) throws Exception{  
03.          
04.        /* 
05.        //获取一个class类对象,使用三种方法中那一中,class类中静态方法 
06.        Class aclass =Class.forName("cn.itcast.Test反射读取配置文件.line2"); 
07.        //由获得Class对象再得到一个该类的一个对象 
08.        Object obj=aclass.getConstructor().newInstance(); 
09.        //得到的该类的一个成员方法 
10.        Method m=aclass.getMethod("move", int.class); 
11.        m.invoke(obj, 20); 
12.        */  
13.          
14.        //定义一个class类对象  
15.        Class aclass=Class.forName(getvalue("classname"));  
16.        //通过反射,并调用构造方法,创建一个该类的对象  
17.        Object obj=aclass.getConstructor(String.class).newInstance("好方法");  
18.        //通过反射调用其成员方法  
19.        aclass.getMethod(getvalue("methodname"), int.class).invoke(obj, 50);          
20.    }  
21.    //通过定义一个方法来获取几种东西  
22.    public static String getvalue(String str)throws IOException{  
23.        //定义一个properties集合map集合,以便于读写文件  
24.        Properties pro=new Properties();  
25.        //定义一个输入流  
26.        FileReader filein=new FileReader(new File("pro.properties"));  
27.        //读取文件中内容到集合中  
28.        pro.load(filein);  
29.        //关闭资源  
30.        filein.close();       
31.        return pro.getProperty(str);  
32.    }  
33.}  
34.public class line2 {  
35.    private String name;  
36.    public line2(String name){  
37.        this.name =name;  
38.    }     
39.    public void move(int n){  
40.        System.out.println("名字是:"+name+"小伙的年龄是"+n);  
41.    }  
42.}  

2.通过泛型越过泛型检查

泛型只是在编译期间有作用,可以通过泛型直接加载其class,往声明泛型的集合添加东西

public class Demo {  
02.    public static void main(String[] args) throws Exception  {  
03.        //定义一个集合  
04.        ArrayList<Integer> list=new ArrayList<>();  
05.        list.add(10);  
06.        //使用反射创建此类的class对象,调用其方法  
07.        Class aclass=ArrayList.class;//list.getclass();  
08.        //获取其方法的对象,使用的参数为object.class,通用的类型  
09.        Method m=aclass.getMethod("add", Object.class);  
10.        m.invoke(list, "nihaoma ");  
11.        System.out.println(list);  
12.    }  
13.}  


3.通过泛型设置某个对象的某个属性为指定值

public class Demo {  
02.    public static void main(String[] args) throws Exception {  
03.        Cat c=new Cat();  
04.        setValue(c,"name","bosimao");  
05.        setValue(c, "age", 2);  
06.        System.out.println("年龄:"+c.getAge()+"名字:"+c.getName());  
07.    }  
08.  
09.  
10.    private static void setValue(Object obj, String fieldName, Object value) throws Exception {  
11.        Class aclass=obj.getClass();  
12.        Field field=aclass.getDeclaredField(fieldName);  
13.        //由于是私有属性,需要暴力访问  
14.        field.setAccessible(true);  
15.        field.set( obj, value);  
16.    }     
17.}  
18.public class Cat {  
19.    private String name;  
20.    private int age=0;  
21.      
22.    public String getName(){  
23.        return this.name;  
24.    }  
25.    public int getAge(){  
26.        return this.age;  
27.    }  
28.}  

五.动态代理

1.动态代理的概述

本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。

在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

2.代理模式:

1).Student类中有一个coding()方法,写程序;
2).测试类中如果需要coding()方法,需要直接实例化一个Student,并调用方法;
如果想在coding()方法的前面或者后面添加一些其他功能,可以不用修改Student类,而为Student类添加
一个"代理类",代理类会调用Student类中的方法。
3).增加了代理类后,测试类不需要直接面对Student,转而使用代理类。代理类中为coding方法添加了新的功能。
实际上就是不直接使用基础类,而是使用第三方代理,并且代理可以添加一些基本功能

public class Demo {//测试类  
02.    public static void main(String[] args) {  
03.        /* 
04.        Student stu = new Student(); 
05.        stu.coding(); 
06.        */  
07.        //使用代理模式  
08.        StudentProxy proxy = new StudentProxy();  
09.        proxy.coding();  
10.    }  
11.}  
12.  
13.  
14.  
15.  
16.public class StudentProxy {//代理类  
17.    public void coding(){  
18.        check();  
19.        new Student().coding();  
20.        zj();  
21.    }  
22.    //先期检查  
23.    public void check(){  
24.        System.out.println("先期检查......");  
25.    }  
26.    //后期总结  
27.    public void zj(){  
28.        System.out.println("后期总结.......");  
29.    }  
30.}  
31.  
32.  
33.  
34.  
35.public class Student {//基础类  
36.    public void coding(){  
37.        System.out.println("做项目,写程序......");  
38.    }  
39.}  

3.动态代理的步骤;

1).自定义一个类,实现InvocationHander接口,并重写接口中的invoke()方法
2).在需要使用代理类的时候,使用Proxy类中的newProxyInstance()方法获取代理类的对象
3).JDK只能为接口做动态代理,所以要为所要代理的类定义一个接口,并去实现接口

public class Demo {//测试类  
02.    public static void main(String[] args) throws Exception {  
03.        //多态的子类对象,使用proxy类中的方法newproxyInstace  
04.          
05.        //Idao idaostu=(Idao) Proxy.newProxyInstance(Class.forName("cn.itcast.Test动态代理.Student").getClassLoader(),   
06.        //                                  Student.class.getInterfaces(),new MyInvocationhander(new Student()));  
07.          
08.        Idao idaostu=(Idao) Proxy.newProxyInstance(Student.class.getClassLoader(),   
09.                                                    Student.class.getInterfaces(),  
10.                                                    new MyInvocationhander(new Student()));  
11.        idaostu.write();//需要使用的方法  
12.    }  
13.}  
14.  
15.  
16.  
17.  
18.public class MyInvocationhander implements InvocationHandler {//实现接口,代理类  
19.      
20.    private Object obj;//定义需要代理的对象  
21.    public MyInvocationhander(Object obj) {  
22.        this.obj=obj;  
23.    }  
24.  
25.  
26.    @Override  
27.    public Object invoke(Object proxy, Method method, Object[] args)  
28.            throws Throwable {  
29.        Object objmethod=method.invoke(obj);  
30.        show();  
31.        return objmethod;  
32.    }  
33.  
34.  
35.    private void show() {  
36.        System.out.println("真是牛叉啊!!");  
37.    }  
38.}  
39.  
40.  
41.public interface Idao {//自己定义接口  
42.    public void write();  
43.}  
44.  
45.  
46.public class Student implements Idao {//自定义类,需要代理的类  
47.          
48.    @Override  
49.    public void write() {  
50.        System.out.println("你好,动态代理!!");  
51.    }  
52.}  


六.枚举

1.枚举概述

一种模式"多例模式":在整个应用程序运行期间,有些类的实例,只允许有固定的几个,这种模式就是"多例模式"
  例如:骰子:需要2个实例;
          扑克:54个实例;        
    现在说的枚举,就是基于"多例模式":  
例如:我们的程序运行期间,需要三个颜色(红\绿\蓝),所以我们使用一个类MyColor来表示颜色。因为我们只需要三个颜色,所以这个类的对象,只能有三个;

public abstract class MyColor3 {//抽象类也是可以定义多例模式  
02.    public static final MyColor3 RED  = new MyColor3("红"){  
03.        @Override  
04.        void show() {  
05.            System.out.println("我是红色的!");  
06.        }};  
07.    public static final MyColor3 GREEN = new MyColor3("绿"){  
08.        @Override  
09.        void show() {  
10.            System.out.println("我是绿色的!");  
11.        }};  
12.    public static final MyColor3 BLUE = new MyColor3("蓝"){  
13.        @Override  
14.        void show() {  
15.            System.out.println("我是蓝色的!");  
16.        }};  
17.    private String colorName;  
18.      
19.    private MyColor3(String colorName){  
20.        this.colorName = colorName;  
21.    }  
22.      
23.    public String toString(){  
24.        return this.colorName;  
25.    }  
26.      
27.    abstract void show();  
28.}  

2.制作枚举步骤:

1).定义枚举:public enum Xxxxx
2).直接定义枚举项。注意:可以有其它成员,但枚举项必须在第一行;
3).枚举中可以包含抽象方法;
4).任何的枚举类,都继承自:Enum类;

public enum MyColor3 {  
02.    RED("红") {  
03.        @Override  
04.        void show() {  
05.            System.out.println("我是红色的!");  
06.        }  
07.    },GREEN("绿") {  
08.        @Override  
09.        void show() {  
10.            System.out.println("我是绿色的!");  
11.        }  
12.    },BLUE("蓝") {  
13.        @Override  
14.        void show() {  
15.            System.out.println("我是蓝色的!");  
16.        }  
17.    };  
18.    private String colorName;  
19.    private MyColor3(String n){  
20.        this.colorName = n;  
21.    }  
22.      
23.    public String getColorName(){  
24.        return this.colorName;  
25.    }  
26.      
27.    abstract void show();  
28.}  

3.枚举类中常用方法,使用枚举对象调用

int compareTo(E o)//比较的是枚举项的索引值,做减法
String name()//枚举项的名字fieldname
int ordinal()//枚举项的索引值
String toString()//枚举对象所对对应的fieldname
<T> T valueOf(Class<T> type,String name)//将一个字符串转换为type类型的对象
values() 
此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便

public class Demo {  
02.    public static void main(String[] args) {  
03.        MyColor3 c1 = MyColor3.RED;  
04.        MyColor3 c2 = MyColor3.BLUE;  
05.          
06.        System.out.println(c2.compareTo(c1));//索引值的减法  
07.        System.out.println("name = " + c2.name());//BLUE  
08.        //int ordinal()  
09.        System.out.println("c2.ordinal() : " + c2.ordinal());  
10.        System.out.println("c1.ordinal() : " + c1.ordinal());  
11.        //String toString()  
12.        System.out.println("c2.toString():" + c2.toString());  
13.        //<T> T valueOf(Class<T> type,String name)  
14.        MyColor3 c3 = c1.valueOf("RED");//将一个字符串转换为MyColor3对象  
15.        MyColor3 c4 = MyColor3.valueOf(MyColor3.class,"BLUE");  
16.          
17.        System.out.println(c3);  
18.        System.out.println(c4);  
19.          
20.        //values()   
21.        MyColor3[] result = c1.values();  
22.        System.out.println("循环遍历:");  
23.        for(MyColor3 c : result){  
24.            System.out.println(c);  
25.        }  
26.    }  
27.}  




                                                              ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------





源码下载地址: https://pan.quark.cn/s/a4b39357ea24 Altium Designer 18是一款功能丰富的电子设计自动化工具,其集成了电路原理图绘制、PCB布局规划、三维视图展示、电路仿真分析以及生产文件生成等多项核心功能,为电子工程师们提供了一个全面的硬件设计解决方案。该软件的官方中文指导材料系统地阐述了从项目初始阶段到最终完成的全过程操作方法。 在“AD18 官方中文指导材料”中,使用者可以掌握以下核心内容要点: 1. **系统配置与界面认知**:熟悉Altium Designer 18的工作平台,涵盖菜单选项、工具栏配置、工作区域安排,以及个性化工作界面的设定方法。 2. **项目创建流程**:掌握如何建立新的项目工程,包括工程参数配置、项目模板选取,以及项目文件的添加操作。 3. **电路图绘制技术**:学习电路原理图的绘制流程,包括元件库的维护管理、元件放置技巧、连接线路绘制、属性编辑操作,以及网络表的自动生成方法。 4. **元件库构建与管理**:了解如何建立自定义元件库,执行元件的导入与导出任务,以及利用Altium Designer自带的元件资源库。 5. **PCB布局设计方法**:掌握PCB设计的基本准则,如元件布局策略、布线技巧、层叠结构调整、布线规则优化,以及冲突检测与短路处理技术。 6. **设计规范与约束条件**:理解设定设计规范和电气约束条件的关键性,包括间距参数设定、焊盘尺寸规格、过孔尺寸要求等,以及运用规则检查进行设计验证的流程。 7. **三维模型整合应用**:学习如何将三维模型与PCB设计内容相结合,以实现更为直观的机械配合验证。 8. **电路性能仿真技术**:掌握使用Altium Des...
源码链接: https://pan.quark.cn/s/a4b39357ea24 ### 接口测试知识要点说明 #### 一、接口测试的定义及分 1. **概念阐释**: - 接口测试作为软件测试的关键环节,主要对系统之间的交互点进行验证。 - 它旨在核实接口的正确性、稳定性和功能性,保障各个系统组件能够依照预期执行交互操作。 2. **实施情境**: - 适用于多系统联合开发的环境。 - 适用于包含多个子系统的复杂应用系统开发过程。 3. **适用范围**: - 为其他系统提供支持的底层基础架构系统。 - 负责协调中心服务的系统架构。 4. **分标准**: - **模块接口测试**:通常作为单元测试的一部分,适用于独立构建的功能模块。 - **Web接口测试**: - **服务端接口测试**:针对客户端与服务器端之间的接口进行验证。 - **外部接口测试**:对第三方提供的接口进行测试,例如支付平台提供的授权登录接口。 5. **测试角度**: - **接口功能验证**:核实接口功能是否满足预期要求。 - **接口性能评估**:衡量接口的处理能力及响应时间。 - **接口稳定性考察**:检测接口在长时间运行中的表现情况。 - **接口安全检测**:确保接口能够抵御非法访问或数据篡改。 6. **测试手法**: - **参数细致测试**:深入测试接口的输入参数和输出结果。 - **场景模拟测试**:依据实际业务场景进行测试验证。 #### 二、接口测试的详细流程 1. **测试规划**: - 明确测试范围、目标及所需资源。 - 规划测试策略,选择适宜的工具和技术手段。 2. **测试用例设计**: - 依据需求文档和接口规格文档设计测试用例。 - 覆...
内容概要:本文研究基于遗传算法(GA)与粒子群算法(PSO)相结合的无人机三维路径规划方法,旨在解决无人机在复杂三维环境中避障与路径优化的关键问题。通过构建包含障碍物、威胁区域等约束的三维仿真环境,系统实现了GA与PSO两种智能优化算法的Matlab代码,并对其在路径规划中的性能进行全面对比分析,重点关注路径长度、飞行安全性、算法收敛速度等核心指标。研究充分利用GA的全局搜索能力与PSO的快速局部收敛特性,提出一种混合优化策略,有效克服单一算法易陷入局部最优或收敛缓慢的缺陷。文中不仅详细阐述了算法的设计流程、数学模型与实现细节,还提供了完整的仿真结果,验证了所提混合方法在复杂动态场景下的优越性、有效性和鲁棒性,为无人机自主导航提供了可靠的理论依据和技术方案。; 适合人群:具备一定Matlab编程基础和优化算法理论知识,从事无人机系统设计、智能控制、路径规划、人工智能应用等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于城市峡谷、山区、灾害救援等复杂三维环境中的无人机自主避障与最优任务路径规划;②为智能优化算法(GA、PSO及其混合策略)的学习、性能对比与工程化应用提供详实的实践案例和代码参考;③服务于高校科研教学、算法原型快速复现、以及在此基础上的进一步改进与创新研究。; 阅读建议:建议读者结合所提供的Matlab代码进行仿真运行与调试,深入理解两种算法的参数设置、适应度函数设计及路径生成机制,可通过修改环境地图、增加动态障碍物或调整优化目标函数等方式进行扩展性研究,以深化对算法本质和应用场景的理解。
内容概要:LTK8870S是一款单通道H桥有刷直流电机驱动器,支持6.5V至20V工作电压,具备3.0A峰值电流驱动能力,适用于打印机、家用电器及工业设备等机电一体化应用。该芯片采用PWM控制接口,可通过IN1和IN2逻辑输入实现电机正转、反转、滑行与制动等多种工作模式,并支持快衰减和慢衰减两种电流衰减方式以优化电机控制性能。器件集成电流调节功能,通过VREF引脚和外部检测电阻设定限流值,有效控制电机电流并降低系统功耗。同时具备低功耗休眠模式,在IN1和IN2均为低电平时自动进入,显著节省能耗。LTK8870S还集成了多重保护机制,包括VM欠压锁定(UVLO)、过温保护(TSD)、过流保护(OCP)及自动故障恢复功能,提升系统可靠性。其ESOP-8封装带裸露焊盘,利于散热,符合无铅环保标准。; 适合人群:电子硬件工程师、电机控制系统开发者、嵌入式系统设计人员,尤其适用于从事电机驱动电路设计的中级技术人员。; 使用场景及目标:①用于控制中小型有刷直流电机的正反转与调速;②应用于需要电流限制和节能休眠功能的电池供电设备;③作为工业自动化、智能家电或办公设备中的核心驱动模块;④帮助开发者理解H桥驱动、PWM调速、电流衰减模式及保护电路的设计原理。; 阅读建议:此资源技术细节丰富,建议结合典型应用电路图与电气参数表进行硬件设计参考,重点关注PWM控制逻辑、电流调节设置及保护机制的实现方式,并在实际应用中配合示波器调试输出波形与电流响应。
内容概要:本文提出了一种基于纳什谈判理论的风–光–氢多主体能源系统合作运行方法,旨在通过合作博弈框架协调风电、光伏与氢能系统之间的运行决策,实现多能源主体在满足个体理性前提下的整体效益最优。研究构建了考虑可再生能源出力随机性与氢能系统动态响应特性的多主体协同优化模型,采用纳什谈判机制设计利益分配规则,有效解决了各方在联合运行中的竞争与协作矛盾。通过Matlab平台完成了模型编程求解与仿真验证,结果表明该方法能够显著提升系统经济性、增强清洁能源消纳能力,并促进多主体间的合作意愿,为高比例可再生能源系统的市场化协同运行提供了理论依据与技术路径。; 适合人群:具备电力系统分析、优化建模与博弈论基础,从事新能源系统调度、综合能源系统规划与运行、能源市场机制设计等方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究风–光–氢多能互补系统的协同优化机制与利益分配策略;②构建基于合作博弈的综合能源系统运行模型并进行仿真分析;③支撑硕士、博士论文复现及高水平学术论文撰写与投稿。; 阅读建议:建议结合Matlab代码深入理解纳什谈判模型的数学建模过程,重点掌握目标函数构造、约束条件处理及均衡求解算法的实现细节,同时可尝试将其拓展至Shapley值等其他合作博弈方法的对比研究,以深化对多主体协同机制的理解。
源码下载地址: https://pan.quark.cn/s/2a998390025c 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值