本文主要介绍的是枚举类,注解和反射。还有一些基础知识:static,基本数据类型,运算符优先级放在文中,以便查阅复习。

其中牵扯到泛型的部分,可参考本人的另一篇博客:(Collection, List, 泛型)JAVA集合框架一

1. static关键字

static可以修饰的有:属性,方法,代码块,内部类。

1.1 static修饰属性

按是否用static修饰分为静态属性和非静态属性(实例变量)。

非静态属性(实例变量):当创建了类的多个对象,每个对象都独立拥有自己的非静态属性。当修改其中一个对象中的非静态属性时,不会改变其他对象中的非静态属性。

静态属性(静态变量):当创建了类的多个对象,多个对象共享同一个静态对象。通过任一个对象改变静态属性,所有对象的静态属性都会发生改变。

  • 静态变量随着类的加载而加载。可通过class.静态变量进行调用。
  • 静态变量的加载早于对象的创建,在创建对象的过程中,才实现实例属性的加载。
  • 由于类只会加载一次,则静态变量在内存中也只会存在一份。存在方法区的静态域中。

1.2 static修饰方法

静态方法:

  • 随着类的加载而加载,可以直接通过类.静态方法调用
  • 静态方法中,只能调用静态的方法或属性,因为它们生命周期相同;非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。

注意点:

  • 在静态的方法内,不能使用thissuper关键字,因为静态方法不需要实例化对象,而没有实例化对象this就没有意义。一定要是同级的生命周期才能使用。

2. 枚举类

JDK5.0新增enum关键字

理解:

  • 类的对象只有有限个、确定的,称此类为枚举类
  • 当需要定义一组常量时,建议使用枚举类

2.1 基本使用

常用方法:

重点掌握:toStringvaluesvalueOf

2.2 enum实现接口

  • 情况一:实现接口,在enum类中实现抽象方法
  1. interface Info{
  2. void show();
  3. }
  4. enum Season implements Info{
  5. @Override
  6. public void show() {
  7. System.out.println("hello,world");
  8. }
  9. }
  • 情况二:让枚举类的对象分别实现接口中的抽象方法

整体demo包含常用方法的使用:

  1. public class EnumTest1 {
  2. public static void main(String[] args) {
  3. Season summer = Season.SUMMER;
  4. System.out.println(summer); //SUMMER
  5. System.out.println(Season.class.getSuperclass()); //class java.lang.Enum
  6. System.out.println(summer.getSeasonFeel()); //hot
  7. Season[] values = Season.values();
  8. for(Object i : values){
  9. System.out.println(i); //SPRING,SUMMER,AUTUMN,WINTER
  10. }
  11. Season winter = Season.valueOf("WINTER"); //根据字符串返回相应的enum,错误则出现异常
  12. System.out.println(winter); //WINTER
  13. winter.show();
  14. }
  15. }
  16. interface Info{
  17. void show();
  18. }
  19. enum Season implements Info{
  20. SPRING("spring","warm"){
  21. @Override
  22. public void show() {
  23. }
  24. },
  25. SUMMER("summer","hot"){
  26. @Override
  27. public void show() {
  28. }
  29. },
  30. AUTUMN("autumn","cool"){
  31. @Override
  32. public void show() {
  33. }
  34. },
  35. WINTER("winter","cold"){
  36. @Override
  37. public void show() {
  38. }
  39. };
  40. private final String SeasonName;
  41. private final String SeasonFeel;
  42. Season(String seasonName, String seasonFeel) {
  43. SeasonName = seasonName;
  44. SeasonFeel = seasonFeel;
  45. }
  46. public String getSeasonName() {
  47. return SeasonName;
  48. }
  49. public String getSeasonFeel() {
  50. return SeasonFeel;
  51. }
  52. }

Thread中线程状态利用的就是枚举类,可参考源码。

3. 注释和注解

注解(Annotation)是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或进行部署。JDK5.0新增

JavaSE中注解的使用目的比较简单,比如标记过时功能,忽略警告等。在JavaEE中占据了更重要的角色。后续博客将会继续JavaEE的内容。

在一定程度上,框架 = 注解 + 反射 + 设计模式

3.1 类注释举例

  1. /**
  2. */

类注释必须放在import语句之后,类定义之前。

3.2 方法注解

除了通用标记之外,还可以使用下面的标记:

@param变量描述,这个标记将对当前方法的参数部分添加一个条目。这个描述可以占据多行,并可以使用HTML标记,一个方法的所有变量描述需要放在一起。

@return描述

@throws类描述,表示这个方法有可能抛出异常。

3.3 通用注解

注意,一定要用 # 分隔类名和方法名,或类名和变量名。

3.4 自定义注解

  1. //1
  2. public @interface MyAnnotation {
  3. String value();
  4. }
  5. @MyAnnotation(value = "hello") //使用时
  6. //2
  7. public @interface MyAnnotation {
  8. String value() default "hello";
  9. }
  10. @MyAnnotation //默认值"hello",可覆盖
  • 注解声明为:@interface
  • 内部定义成员,通常用value表示
  • 可以指定成员的默认值,使用default定义
  • 如果自定义注解里没有成员,表明是一个标识作用

具体用途在反射和框架中。自定义注解必须配上注解的信息处理流程(使用反射)才有意义。

3.5 JDK提供的4种元注解

元注解:用于修饰其他注解定义

例:

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.SOURCE)
  3. public @interface Override {
  4. }

JDK5.0提供了4个标准的元注解:

Retention, Target, Documented, Inherited


自定义注解通常都会使用以上两个元注解Retention, Target。

3.6 JDK8中注解的新特性

可重复注解

Repeatable()

  1. @Repeatable(MyAnnotations.class)
  2. public @interface MyAnnotation {
  3. String value() default "hello";
  4. }
  5. public @interface MyAnnotations {
  6. MyAnnotation[] value();
  7. }

其中,MyAnnotation和MyAnnotations需要保持Retention和Target以及Inherited一致,在这部分只需要注意,在以后用到时再重点讲解。

类型注解

4. 反射

4.1 反射的基本概念

反射机制提供的功能:

  • 运行时判断任意一个对象所属的类
  • 运行时构造任意一个类的对象
  • 运行时判断任意一个类所具有的成员变量和方法
  • 运行时获取泛型信息
  • 运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

关于java.lang.Class类的理解:

  • 类的加载过程:程序经过javac.exe命令后(编译),会生成一个或多个字节码文件(.class文件)。接着使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程成为类的加载。加载到内存中的类,称为运行时类,此运行时类,作为Class的一个实例。
  • Class的实例对应着一个运行时类
  • 加载到内存中的运行时类,会缓存一定的时间。在此时间内,可以通过不同方式来获取Class的实例。
  • Object是所有类的父类,而Class是类的类。

三种Class实例的获取方式:

获取当前对象的类型对象,类型类是指代表一个类型的类,获取class对象的方法有:1.类名.class,所有的引用数据类型和基本数据类型都可以通过这个方式获取。2.通过对象实例.getClass()来获得class对象。3.调用Class的静态方法 Class.forName(String classPath)

例:

  1. //调用运行时类的属性, .class
  2. Class<Person> clazz1 = Person.class;//泛型可省略
  3. System.out.println(clazz1); //class demo1.Person
  4. //通过运行时类的对象
  5. Person p1 = new Person();
  6. Class clazz2 = p1.getClass();
  7. System.out.println(clazz2);
  8. //调用Class的静态方法 Class.forName(String classPath)
  9. Class clazz3 = Class.forName("demo1.Person");
  10. System.out.println(clazz3);

此外,还可以使用类的加载器ClassLoader,不再详细赘述。

JDK8中对于自定义类的ClassLoader属于系统类加载器,此外还有扩展类加载器和引导类加载器。

简述下方的Person类:内部成员变量为public String name, private int age, 有公有构造器和私有构造器,有公有方法show()和私有方法show1(), 重写toString。

基本应用demo:

  1. Class clazz = Person.class; //public age,private name
  2. //通过反射,创建Person类的对象
  3. Constructor cons = clazz.getConstructor(String.class,int.class);
  4. Object obj = cons.newInstance("Tom",12);
  5. Person p = (Person) obj;
  6. System.out.println(p.toString()); //Person{name='Tom', age=12} 调用了Person类中的toString方法
  7. System.out.println(cons); //public demo1.Person(java.lang.String,int)
  8. //通过反射,调用对象指定的属性,方法
  9. Field age = clazz.getDeclaredField("age");
  10. age.set(p,10);
  11. System.out.println(p.toString()); //Person{name='Tom', age=10}
  12. Method show = clazz.getDeclaredMethod("show");
  13. show.invoke(p); //sout("hello")

需要注意的是Class对象并不能指明该类型的实例化,需要在FieldMethod这种将实例放入参数中。

4.2 反射调用私有结构

通过反射,可以调用Person类的私有结构,如:私有构造器,私有方法,私有属性。

  1. //调用私有构造器
  2. Constructor cons1 = clazz.getDeclaredConstructor(String.class);
  3. cons1.setAccessible(true);
  4. Person p1 = (Person)cons1.newInstance("tim");
  5. System.out.println(p1); //Person{name='tim', age=0}
  6. //调用私有属性
  7. Field name = clazz.getDeclaredField("name");
  8. name.setAccessible(true);
  9. name.set(p1,"Tim");
  10. System.out.println(p1); //Person{name='Tim', age=0}
  11. //调用私有方法
  12. Method show1 = clazz.getDeclaredMethod("show1",String.class);
  13. show1.setAccessible(true);
  14. show1.invoke(p1,"H"); //world H,相当于p1.show1("H");
  15. //.invoke返回的是object,强制转换
  16. String str = (String)show1.invoke(p1,"H");
  17. System.out.println(str); //H,p1.show1(str)返回了str。

这里和面向对象概念中的封装性可能有冲突,为什么要利用反射呢?

举个例子:反射具有动态性的特征。后台中,服务器的程序一直运行,假如从前端传来信息,后台就可以动态进行调用。动态过程中,可以利用反射进行应用。

4.3 反射的相关操作

通过反射创建运行时类的对象

  1. Class<Person> clazz = Person.class;//使用泛型声明后下方不用强制转换,Person有public的空参构造器
  2. Person obj = clazz.newInstance();//Person{name='null', age=0},内部其实调用了运行时类的空参构造器
  3. System.out.println(obj);

获取运行时类的完整结构

  1. Class clazz = Person.class;
  2. //获取属性结构
  3. //.getFields() 获取当前运行时类及其父类中声明为Public访问权限的属性
  4. Field[] fields = clazz.getFields(); //public int demo1.Person.id, public double demo1.Creature.weight,只有public属性
  5. for(Field f : fields){
  6. System.out.println(f);
  7. }
  8. //.getDeclaredFields() 获得当前运行类中声明的所有属性(不包含父类)
  9. Field[] declaredfields = clazz.getDeclaredFields();//省略为:name,age,id
  10. for(Field f : declaredfields){
  11. System.out.println(f);
  12. }
  1. Field[] declaredfields = clazz.getDeclaredFields();
  2. for(Field f : declaredfields){
  3. //1.权限修饰符
  4. int modifier = f.getModifiers(); //修饰符以int表示,Modifier类中有相关代码
  5. System.out.println(Modifier.toString(modifier)); //这样的话就可以正常显示public,private等了
  6. //数据类型
  7. Class type = f.getType();
  8. System.out.println(type.getName()); //也可直接用type
  9. //变量名
  10. System.out.println(f.getName());
  11. }

获得方法结构:

  1. Class clazz = Person.class;
  2. //获取当前运行时类和父类的Public方法
  3. Method[] methods = clazz.getMethods();
  4. for(Method m : methods){
  5. System.out.println(m);
  6. }
  7. //获取当前运行时类声明的所有方法(不包含父类)
  8. Method[] methods1 = clazz.getDeclaredMethods();
  9. for(Method m : methods1){
  10. System.out.println(m);
  11. }

获取方法的内部结构:

  1. Method[] methods = clazz.getDeclaredMethods();
  2. for(Method m : methods){
  3. //获取方法声明的注解
  4. Annotation[] anno = m.getAnnotations();
  5. for(Annotation i : anno){
  6. System.out.println(i);
  7. }
  8. //得到每个方法的权限修饰符
  9. System.out.println(Modifier.toString(m.getModifiers()));
  10. //返回值类型
  11. System.out.println(m.getReturnType().getName());
  12. //方法名
  13. System.out.println(m.getName());
  14. //形参列表
  15. Class[] paras = m.getParameterTypes();
  16. //抛出的异常
  17. Class[] exs = m.getExceptionTypes();
  18. }

构造器等都类似,不再赘述。构造器的.getConstructors和.getDeclaredConstructors不能获取父类的结构,没有意义。

此外还可获取运行时类的父类和父类的泛型,运行时类的接口,包,注释等,代码比较机械,不再赘述。

4.4 调用运行时类的指定结构

调用运行时类的属性:

  1. Class clazz = Person.class;
  2. Person p = (Person) clazz.newInstance();
  3. //.getField只能获取public,获取其他的话需要用.getDeclaredField()
  4. //此外,假如下方是获取所有属性,则需要继续扩展权限,调用id.setAccessible(true);
  5. Field id = clazz.getField("id");
  6. //设置当前属性的值
  7. id.set(p,12);
  8. int i = (int)id.get(p); //返回object,需要强转
  9. System.out.println(i);

调用运行时类中指定的方法:

  1. Class clazz = Person.class;
  2. Person p = (Person) clazz.newInstance();
  3. //获取指定的某个方法
  4. Method m = clazz.getDeclaredMethod("show1",String.class,String.class);
  5. m.setAccessible(true);
  6. //注意: .getDeclaredMethod,.invoke均需要两个参数
  7. //需要注意的是如果方法有多个参数,需要全部标出来
  8. m.invoke(p,"hello","hi"); //返回一个Object,可强转方法的返回类型
  1. //调用静态方法
  2. //private static void show1()
  3. Method m = clazz.getDeclaredMethod("show1");
  4. m.setAccessible(true);
  5. m.invoke(Person.class);//写null也可以,不影响

如果调用的运行时类的方法没有返回值,则返回null

调用运行时类中指定的构造器:

  1. Class<Person> clazz = Person.class;
  2. Constructor cons = clazz.getDeclaredConstructor(String.class);
  3. cons.setAccessible(true);
  4. Person p = (Person) cons.newInstance("hi"); //Person{name='hi', age=0}
  5. System.out.println(p);

需要注意的是即使Class加上泛型声明,下方的Constructor.newInstance仍需强转

接下来是最近刷题时总结了一些基础知识,需要对这些数据保持敏感。

5. 基本数据类型

byte

  • 1个字节,8位、有符号的,以二进制补码表示的整数;
  • 最小值是 -128(-2^7)
  • 最大值是 127(2^7-1)
  • 默认值是 0
  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
  • 例子:byte a = 100,byte b = -50。

short

  • 2个字节,16 位、有符号的以二进制补码表示的整数
  • 最小值是 -32768(-2^15)
  • 最大值是 32767(2^15 - 1)
  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
  • 默认值是 0
  • 例子:short s = 1000,short r = -20000。

int:整数型,4个字节32位,负数以补码形式存在,取值范围如下:

  • 最小值是 -2,147,483,648(-2^31)
  • 最大值是 2,147,483,647(2^31 - 1)
  • 默认值为0

long

  • 8个字节, 64 位、有符号的以二进制补码表示的整数;
  • 最小值是 -9,223,372,036,854,775,808(-2^63)
  • 最大值是 9,223,372,036,854,775,807(2^63 -1)
  • 这种类型主要使用在需要比较大整数的系统上;
  • 默认值是 0L
  • 例子: long a = 100000L,Long b = -200000L。

"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。

float

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
  • float 在储存大型浮点数组的时候可节省内存空间;
  • 默认值是 0.0f
  • 浮点数不能用来表示精确的值,如货币;
  • 例子:float f1 = 234.5f。

double

  • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;
  • 浮点数的默认类型为 double 类型;
  • double类型同样不能表示精确的值,如货币;
  • 默认值是 0.0d

boolean

  • boolean数据类型表示一位的信息;
  • 只有两个取值:true 和 false;
  • 这种类型只作为一种标志来记录 true/false 情况;
  • 默认值是 false
  • 例子:boolean one = true。

char

  • char 类型是一个单一的 16 位 Unicode 字符;
  • 最小值是 \u0000(左方是16进制表示,十进制等效值为 0);
  • 最大值是 \uffff(即为 65535);
  • char 数据类型可以储存任何字符;
  • 例子:char letter = 'A';。

6. 运算符优先级

Java枚举类、注解和反射的更多相关文章

  1. Java枚举类在生产环境中的使用方式

    前言   Java枚举在项目中使用非常普遍,许多人在做项目时,一定会遇到要维护某些业务场景状态的时候,往往会定义一个常量类,然后添加业务场景相关的状态常量.但实际上,生产环境的项目中业务状态的定义大部 ...

  2. 枚举类&&注解&&反射

    什么是枚举类? 枚举类是优化定义固定对象的一种特殊的类. 换句话说,在需要类的实例为一个或者多个并且相对固定的时候,使用枚举类.(枚举类可扩展) 类的实例相对来说固定的有日期,客观不变的一些数字等等. ...

  3. Java枚举类和注解梳理

    1. 枚举类 1. 枚举类的使用 枚举类的理解:类的对象只有有限个,确定的.我们称此类为枚举类. 当需要定义一组常量时,强烈建议使用枚举类. 如果枚举类中只有一个对象,则可以作为单例模式的实现方式. ...

  4. Java枚举类与注解详解——一篇文章读懂枚举类与注解详

    目录 一.枚举类 ① 自定义枚举类 ② enum关键字定义枚举类 ③ enum 枚举类的方法 ④ enum 枚举类实现接口 二.注解 ① 生成文档相关注解 ②注解在编译时进行格式检查 ③注解跟踪代码的 ...

  5. Enum枚举类|注解Annotation

    Enum枚举类 ①枚举类和普通类的差别: 使用 enum 定义的枚举类默认继承了 java.lang.Enum 类 枚举类的构造器仅仅能使用 private 訪问控制符 枚举类的全部实例必须在枚举类中 ...

  6. 第8章 枚举类&注解

    8.枚举及注解 8.1 如何自定义枚举类 1课时 8.2 如何使用关键字enum定义枚举类 1课时 8.3 枚举类的主要方法 1课时 8.4 实现接口的枚举类 1课时 8-1 枚举类 枚举类入门 枚举 ...

  7. Java学习笔记--注解和反射

    注解和反射 1. 注解 注解作用: 对程序做出解释 被其他程序读取 注解格式: @注释名,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked&qu ...

  8. Java利用自定义注解、反射实现简单BaseDao

    在常见的ORM框架中,大都提供了使用注解方式来实现entity与数据库的映射,这里简单地使用自定义注解与反射来生成可执行的sql语句. 这是整体的目录结构,本来是为复习注解建立的项目^.^ 好的,首先 ...

  9. 【Java】利用注解和反射实现一个"低配版"的依赖注入

    在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个“低配版”的依赖注入. 下面是我们 ...

随机推荐

  1. IPFS挖矿靠谱吗?

    IPFS是一个旨在创建持久且分布式存储和共享文件的网络传输协议,前景广阔且实用意义大,为区块链行业提供了一种新的可能.而IPFS挖矿挖出的FIL,则是在IPFS技术的基础上,对维护IPFS网络的用户的 ...

  2. TEB 、TIB、PEB--Vista 32

    TEB struct TEB typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVO ...

  3. limanmanExp数据库审计设计思路与重要代码

    目的 在代码审计的时候经常会想看看某个访问会触发哪些数据库操作.目前已知的数据库审计有多家大型厂商的设备,还有seay源码审计系统中的数据库监控1.0 但是.开源的已知的就只有seay源码审计系统中的 ...

  4. 显示IPC信息--ipcs

    ipcs                                       显示共享内存,消息队列, 信号量全部的IPC ipcs -q                            ...

  5. List集合中的交集 并集和差集

    目录 List集合求交集 并集 差集 Set集合 Lambda表达式 List集合求交集 并集 差集 两种方法求集 Set集合 交集 两个集合中有相同的元素 抽取出来的数据就是为交集 @Test pu ...

  6. Ansible-Playbook中的变量使用

    变量名:仅能由字母.数字和下划线组成,且只能以字母开头 变量来源: 1.ansible all -m setup 远程主机的所有变量都可直接调用 #显示所有变量 ansible all -m setu ...

  7. Python-Tkinter 使用for循环生成列表式Button及函数调用

    Tkinter是轻量级的图形化界面,在使用中我们可能遇到需要生成一串Button按钮的情况,如图: 如果一个一个操作就太麻烦了,但我们可以通过for循环列表的形式来实现 来看看以下例子: from t ...

  8. SQLserver数据库安装教程

    大家好,这期给大家带来一期SQL server的安装教程 下载SQL Server 2019 Developer 官方网址: https://www.microsoft.com/zh-cn/sql-s ...

  9. get_started_3dsctf_2016-Pwn

    get_started_3dsctf_2016-Pwn 这个题确实有点坑,在本地能打,在远程就不能打了,于是我就换了另一种方法来做. 确这个题是没有动态链接库,且PIE是关的,所以程序的大部分地址已经 ...

  10. 1. Mybatis 参数传递

    方法1:顺序传参法 public User selectUser(String name, int deptId); <select id="selectUser" resu ...