广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Java和C++的枚举与反射有什么不同
  • 679
分享到

Java和C++的枚举与反射有什么不同

2023-06-17 12:06:50 679人浏览 独家记忆
摘要

这篇文章主要介绍“Java和c++的枚举与反射有什么不同”,在日常操作中,相信很多人在Java和C++的枚举与反射有什么不同问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java和C++的枚举与反射有什么不同

这篇文章主要介绍“Java和c++的枚举与反射有什么不同”,在日常操作中,相信很多人在Java和C++的枚举与反射有什么不同问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java和C++的枚举与反射有什么不同”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、枚举:

枚举的是在Java 1.5SE 中开始支持的,以下为Java枚举的基本概念和应用技巧:

   所有的enum对象均是由class对象作为底层支持的,该对象继承自jdk中的Enum<E>,但是该底层类确实final类,既不能再被其他的类继承。

   枚举的出现完全替代了原有的"public static final"常量表示法,枚举以一种更加合理、优雅和安全的方式替换了原有的方案。其最基本的声明方式如下:

public enum Color { RED, BLUE, BLACK, YELLOW }

   Enum<E>中构造函数的原型为protected Enum(String name, int ordinal),自定义的枚举对象会将自身的名字以字符串的形式,同时将自己在整个常量从声明的顺序作为超类构造函数的两个参数传给超类并由超类完成必要的初始化,如:RED枚举常量将调用super("RED",0)。

   枚举中可以定义构造函数、域方法和域字段,但是枚举中的构造器必须是私有(private)的,如果自定义枚举中有了自定义的构造函数,那么每个枚举常量在声明时必须按照自定义构造函数的规则传入参数。枚举对象的构造函数只是在枚举常量对象声明的时刻才调用一次,之后再也不能像普通对象那样通过new的方法创建,见如下代码:

public enum Size { SMALL(0.8), MEDIUM(1.0), LARGE(1.2); double pricingFactor; private Size(double p) { pricingFactor = p; } }

注:枚举常量列表必须写在最前面声明,否则编译器报错。

   可以给自定义枚举添加域方法,见如下代码:

public enum Size { SMALL(0.8), MEDIUM(1.0), LARGE(1.2); private double pricingFactor; Size(double p) { pricingFactor = p; } public double getPricingFactor() { return pricingFactor; } }

   枚举中常用域方法:

public enum Size{ SMALL, MEDIUM, LARGE; } public static void main(String[] args){ //两种获得枚举类型的方法 Size s1 = Size.SMALL; //valueOf的函数原型为<T extends Enum<T>> T valueOf(Class<T> enumType,String name) Size s2 = Enum.valueOf(Size.class, "SMALL"); //Size(自定义枚举)的valueOf方法是Java编译器在生成字节码的时候自动插入的。 Size s3 = Size.valueOf("MEDIUM");//1  //结果同上,枚举重载了equals方法 System.out.println("Size.MEDIUM.equals(Enum.valueOf(Size.class, \"MEDIUM\")):"+ Size.MEDIUM.equals(Enum.valueOf(Size.class, "MEDIUM")));  //遍历枚举类型中所有的成员,这里应用的Size.values方法和Size.valueOf方法 //一样均是编译器在生成字节码的时候自动插入的。 for(Size s:Size.values()){//2 //ordinal()和name()方法均为Enum提供的方法,返回枚举常量在声明时的构 //造函数中自动调用超类构造函数时传入的自身字符串名和在声明列表中的序号 System.out.println(s.ordinal()+" "+s.name()+" "+s.toString()); } //compareTo方法缺省比较的是枚举常量的ordinal()的返回值。 if (s1.compareTo(s3) < 0) System.out.println("Size.SMALL is less than Size.MEDIUM"); }

   在枚举中可以声明基于特定常量的类主体,见如下代码:

public enum Size { //Small、ExtraLarge和ExtraExtraLarge均使用自定义的getPricingFactor //方法覆盖Size提供的缺省getPricingFactor方法。 Small { @Override public double getPricingFactor() { return 0.8; } }, //Medium和Large将使用Size内部缺省实现的getPricingFactor方法。 Medium, Large, ExtraLarge { @Override public double getPricingFactor() { return 1.2; } }, ExtraExtraLarge { @Override public double getPricingFactor() { return 1.2; } }; public double getPricingFactor() { return 1.0; } } public static void main(String args[]) { for (Size s : Size.values()) { double d = s.getPricingFactor(); System.out.println(s + " Size has pricing factor of " + d); } } 

   枚举在switch语句中的用法,见如下代码:

public enum Color { RED, BLUE, BLACK, YELLOW } public static void main(String[] args) { Color m = Color.BLUE; //case语句中引用枚举常量时不需要再加上枚举的类型名了。 switch (m) {     case RED: System.out.println("color is red"); break; case BLACK: System.out.println("color is black"); break; case YELLOW: System.out.println("color is yellow"); break; case BLUE: System.out.println("color is blue"); break; default: System.out.println("color is unknown"); break; } }

   和枚举相关的两个容器EnumMap和EnumSet,声明和主要用法如下。

EnumMap<K extends Enum<K>, V>  EnumSet<E extends Enum<E>> //Code Example 1 public enum State {  ON, OFF  };  public static void main(String[] args) {  //EnumSet的使用  EnumSet stateSet = EnumSet.allOf(State.class);  for (State s : stateSet) System.out.println(s);   //EnumMap的使用  EnumMap stateMap = new EnumMap(State.class);  stateMap.put(State.ON, "is On");  stateMap.put(State.OFF, "is off");  for (State s : State.values())  System.out.println(s.name() + ":" + stateMap.get(s));  }  //Code Example 2 public enum Size { Small,Medium,Large } public static void main(String args[]) { Map<Size, Double> map = new EnumMap<Size, Double>(Size.class); map.put(Size.Small, 0.8); map.put(Size.Medium, 1.0); map.put(Size.Large, 1.2); for (Map.Entry<Size, Double> entry : map.entrySet()) helper(entry); } private static void helper(Map.Entry<Size, Double> entry) { System.out.println("Map entry: " + entry); }

   Java枚举和C++枚举的主要区别为两点,一是C++中的枚举中只能定义常量,主要用于switch子句,二是C++中的枚举常量可以直接和数值型变量进行各种数学运算。

二、反射:

   Java的反射机制主要表现为四点:

1)    在运行中分析类的能力;

2)    在运行中查看对象;

3)    实现数组的操作代码;

4)    利用Method对象,这个对象很像C++中的函数指针。

注:Java的基于反射的应用主要用于一些工具类库的开发,在实际的应用程序开发中应用的场景较少。

   获取对象的名称(字符串形式) vs 通过对象的名称(字符串形式)创建对象实例,见如下代码:

public static void main(String args[]) { //1. 通过对象获取其字符串表示的名称  Date d = new Date();   //or Class<? extends Date> c1 = d.class; Class<? extends Date> c1 = d.getClass();  String className = c1.getName();  //2. 通过字符串形式的名称创建类实例。 className = "java.util." + className; try { Class c2 = Class.forName(className); //这里用到的newInstance用于创建c2所表示的对象实例,但是必须要求待创建的类实例 //具有缺省构造函数(无参数),很明显newInstance调用并未传入任何参数用于构造对象。 Date d2 = (Date)c2.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }

如果需要通过调用带有参数的构造函数来创建对象实例,需要使用java.lang.reflect.Constructor对象来完成,见如下代码:

public static void main(String args[]) { String className = "java.util.Date"; try { Class c2 = Class.forName(className); //找到只接受一个long类型参数的构造器 Constructor cc = c2.getConstructor(long.class); long ll = 45L; //将该Constructor期望的指定类型(long)的参数实例传入并构造Date对象。 Date dd = (Date)cc.newInstance(ll); System.out.println("Date.toString = " + dd); } catch (Exception e) { e.printStackTrace(); } }

   遍历一个未知类型的所有域、构造方法和域方法,见如下函数原型:

Field[] getFields(); 返回指定对象域字段数组,主要包含该类及其超类的所有公有(public)域。

Field[] getDeclaredFields();返回指定对象域字段数组,主要包含该类自身的所有域,包括private等。

Method[] getMethods(); 返回指定对象域方法数组,主要包含该类及其超类的所有公有(public)域方法。

Method[] getDeclaredMethods();返回指定对象域方法数组,主要包含该类自身的所有域方法,包括private等。

Constructor[] getConstructors(); 返回指定对象构造函数数组,主要包含该类所有公有(public)域构造器。

Constructor[] getDeclaredConstructors();返回指定对象构造函数数组,主要包含该类所有域构造器。

int getModifiers(); 返回一个用于描述构造器、方法或域的修饰符的整型数值,使用Modifier类中的静态方法可以协助分析这个返回值。

String getName(); 返回一个用于描述构造器、方法和域名的字符串。

Class[] getParameterTypes(); 返回一个用于描述参数类型的Class对象数组。

Class[] getReturnType(); 返回一个用于描述返回值类型的Class对象。

private static void printConstructors(Class c1) { Constructor[] constructors = c1.getDeclaredConstructors(); for (Constructor c : constructors) { String name = c.getName(); System.out.print(" "); String modifiers = Modifier.toString(c.getModifiers()); if (modifiers.length() > 0) System.out.print(modifiers + " "); System.out.print(name + "(");  Class[] paramTypes = c.getParameterTypes(); for (int j = 0; j < paramTypes.length; ++j) { if (j > 0) System.out.print(","); System.out.print(paramTypes[j].getName()); } System.out.println(");"); } }  private static void printMethods(Class c1) { Method[] methods = c1.getDeclaredMethods(); for (Method m : methods) { Class retType = m.getReturnType(); String name = m.getName(); System.out.print(" ");  String modifiers = Modifier.toString(m.getModifiers()); if (modifiers.length() > 0) System.out.print(modifiers + " "); System.out.print(retType.getName() + " " + name + "("); Class[] paramTypes = m.getParameterTypes(); for (int j = 0; j < paramTypes.length; ++j) { if (j > 0)  System.out.print(", "); System.out.print(paramTypes[j].getName()); } System.out.println(");"); } }  private static void printFields(Class c1) { Field[] fields = c1.getDeclaredFields(); for (Field f : fields) { Class type = f.getType(); String name = f.getName(); System.out.print(" "); String modifiers = Modifier.toString(f.getModifiers()); if (modifiers.length() > 0) System.out.print(modifiers + " "); System.out.println(type.getName() + " " + name + ";"); } }  public static void main(String args[]) { String name = "java.lang.Double"; try { Class c1 = Class.forName(name); Class superc1 = c1.getSuperclass(); String modifier = Modifier.toString(c1.getModifiers()); if (modifier.length() > 0) System.out.print(modifier + " ");  System.out.print("class " + name); if (superc1 != null && superc1 != Object.class) System.out.print(" extends " + superc1.getName());  System.out.print("\n{\n"); printConstructors(c1); System.out.println(); printMethods(c1); System.out.println(); printFields(c1); System.out.println("}"); } catch (Exception e) { e.printStackTrace(); } } 

   通过反射编写泛型数组代码,见如下代码比较:

static Object[] badArrayGrow(Object[] a) { int newLength = a.length * 11 / 10 + 10; //该对象数组的在创建时是基于Object的,所以返回后, //再装回其他类型数组时将会抛出ClassCastException的异常。 Object[] newArray = new Object[newLength]; System.arraycopy(a,0,newArray,0,a.length); return newArray; }  static Object GoodArrayGrow(Object a) {//这里的参数务必为Object,而不是Object[]  Class c1 = a.getClass(); if (!c1.isArray())  return null; //这里用于获取数组成员的类型 Class componentType = c1.getComponentType(); //获取数组的长度。 int length = Array.getLength(a); int newLength = length * 11 / 10 + 10; //通过数组成员的类型和新的长度值来创建一个和参数类型相同的数组, //并增加他的空间,***再返回。 Object newArray = Array.newInstance(componentType,newLength); System.arraycopy(a,0,newArray,0,length); return newArray; }

   在运行时使用反射的对象或动态调用反射之后的方法。

1)    获取域字段和设置域字段:

public void testField() { Employee harry = new Employee("Harry Hacker",35000,10); Class c1 = harry.getClass(); Field f = c1.getDeclaredField("name"); //由于name字段有可能是Employee类的私有域字段,如果直接调用会致使JVM //抛出安全异常,为了避免该异常的发生,需要调用下面的语句来得以保证。 f.setAccessible(true); Object v = f.get(harry); System.out.println(v); }

2)    通过Method的invoke函数动态调用反射后的方法:

该方式有些类似于C#的委托(delegate)和C++的函数指针。

public int add(int param1, int param2) {  return param1 + param2;  }   public static void main(String[] args) throws Exception {  Class classType = MyTest.class;  Object myTest = classType.newInstance();  Method addMethod = classType.getMethod("add",int.class,int.class); //如果add为静态方法,这里的***个参数传null Object result = addMethod.invoke(myTest, 100,200);  System.out.println(result);  }

   C++自身并没有提供像Java这样完备的反射机制,只是提供了非常简单的动态类型信息,如type_info和typeid。然而在一些C++的第三方框架类库中提供了类似的功能,如MFC、Qt。其中MFC是通过宏的方式实现,QT是通过自己的预编译实现。在目前的主流开发语言中,也只有C#提供的反射机制可以和Java的相提并论。

到此,关于“Java和C++的枚举与反射有什么不同”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java和C++的枚举与反射有什么不同

本文链接: https://www.lsjlt.com/news/288822.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java和C++的枚举与反射有什么不同
    这篇文章主要介绍“Java和C++的枚举与反射有什么不同”,在日常操作中,相信很多人在Java和C++的枚举与反射有什么不同问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java和C++的枚举与反射有什么不同...
    99+
    2023-06-17
  • Java和C#有什么不同
    小编给大家分享一下Java和C#有什么不同,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java和C#都提供了对网络的不同抽象层,编程人员可以使用不同的网络接口完...
    99+
    2023-06-03
  • Java语言与C语言有什么不同
    Java语言与C语言有什么不同?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。 Java和C语言虽有相同性,但两者也有一定的不同。Java程序是面向对象的一种简单、...
    99+
    2023-05-31
    java c语言 ava
  • Java中RTTI与反射机制的区别有什么
    今天就跟大家聊聊有关Java中RTTI与反射机制的区别有什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。RTTI,即Run-Time Type Identification,运行时...
    99+
    2023-05-31
    java rtti 反射机制
  • Java中的==与equals有什么不同
    这篇文章给大家介绍Java中的==与equals有什么不同,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java中==运算符与equals方法的区别及intern方法详解  ==运算符与equals()方法2...
    99+
    2023-05-31
    java == equals
  • Java和C++的泛型程序设计有什么不同
    这篇文章主要讲解了“Java和C++的泛型程序设计有什么不同”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java和C++的泛型程序设计有什么不同”吧!泛型程序设计:   &nbs...
    99+
    2023-06-17
  • C#与Flex的访问权限有什么不同
    本篇内容介绍了“C#与Flex的访问权限有什么不同”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在类型内部,对象方法可以自由的访问任何权限成...
    99+
    2023-06-17
  • C++中NULL与nullptr的区别有什么不同
    这篇文章主要介绍C++中NULL与nullptr的区别有什么不同,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、C程序中的NULL在C语言中,NULL通常被定义为:#define NULL ((void *)0)所...
    99+
    2023-06-15
  • Python和 c++/c/java对于负数的存储方式有什么不同
    本篇内容主要讲解“Python和 c++/c/java对于负数的存储方式有什么不同”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python和 c++/c/java对于负数的存储方式有什么不同”...
    99+
    2023-06-03
  • Java的深拷贝与浅拷贝有什么不同
    在Java中,深拷贝和浅拷贝是两种不同的复制方式。浅拷贝是指将对象的引用复制给另一个对象,这样新对象和原对象引用的是同一个内存地址,...
    99+
    2023-08-18
    Java
  • Java中的String 与 new String()有什么不同的地方
    这篇文章给大家介绍Java中的String 与 new String()有什么不同的地方,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java String 和 new String()的区别栈区存引用和基本类型,不能...
    99+
    2023-05-31
    java string new string()
  • Kotlin注解与java注解有什么不同的地方
    本篇文章为大家展示了Kotlin注解与java注解有什么不同的地方,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Kotlin 的注解完全兼容 Java 的注解。声明注解@Target(Annotat...
    99+
    2023-05-31
    kotlin 注解 java
  • Java中的位运算与移位运算有什么不同
    位运算和移位运算都是Java中常用的操作符,但它们执行的操作是不同的。位运算(bitwise operation)是直接对操作数的每...
    99+
    2023-08-15
    Java
  • Java中的面向过程与面向对象有什么不同
    Java中的面向过程与面向对象有什么不同?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。面向过程是指,允许在程序中定义函数或者方法。也许你觉得奇怪,难道还有语言不能定义函数方法么...
    99+
    2023-05-31
    面向对象 面向过程 java
  • java中int转string与string转int的效率有什么不同
    这篇文章将为大家详细讲解有关java中int转string与string转int的效率有什么不同,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。int转string与string转int的效率对比strin...
    99+
    2023-06-29
  • Bash中的Path对象与Java中的Path对象有什么不同?
    Path对象在编程中是一个非常常见的数据类型,它代表着一个文件路径或者目录路径。在不同的编程语言中,Path对象的实现方式也有所不同。本文将会探讨Bash中的Path对象与Java中的Path对象的异同点。 Bash中的Path对象 在B...
    99+
    2023-09-21
    path 对象 bash
  • Java中final、finally和finalize关键字有什么不同的地方
    这篇文章给大家介绍Java中final、finally和finalize关键字有什么不同的地方,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。final当这个关键字修饰一个类时,意味着他不能派生出新的子类,也就是说不能被...
    99+
    2023-05-31
    java finally final
  • Java不同版本接口语法和抽象类与接口的区别是什么
    本文小编为大家详细介绍“Java不同版本接口语法和抽象类与接口的区别是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java不同版本接口语法和抽象类与接口的区别是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-06-29
  • 什么是Java程序的主类,应用程序和小程序的主类有何不同
    一、什么是Java程序的主类 一个程序中可以有多个类,但只能有一个类是主类。 Java主类是含有main函数的类,是Java应用程序的入口点。一个Java程序可能包含很多类,每个类都可以有自己的main函数,但只有含有main函数的类才是J...
    99+
    2023-10-29
    程序 应用程序 有何不同
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作