Java面试题反射

Java反射机制允许在运行时分析类和对象,提供动态类型判断、动态加载类和调用方法的能力。它在性能上有一定损失,但广泛应用于框架设计,如Spring。字符串常量池用于存储字符串常量,提高内存效率。String是不可变的,具有常量池优化和final特性,适用于多线程环境。在内存管理上,String与StringBuilder/StringBuffer有区别,后者适合大量数据操作,线程安全问题需考虑。
摘要由CSDN通过智能技术生成

反射

什么是反射机制?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个

对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为

java语言的反射机制。

静态编译和动态编译

静态编译:在编译时确定类型,绑定对象

动态编译:运行时确定类型,绑定对象

反射机制优缺点

优点: 运行期类型的判断,动态加载类,提高代码灵活度。

缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能

比直接的java代码要慢很多。

反射机制的应用场景有哪些?

反射是框架设计的灵魂。

在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实

际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代

理设计模式也采用了反射机制,还有我们日常使用的 SpringHibernate 等框架也大量使用到了反射机

制。

举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;

Spring框架也用到很多反射机制, 经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean

的过程:1) 将程序内所有 XML  Properties 配置文件加载入内存中; 2)Java类里面解析xml

properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这

个字符串获得某个类的Class实例; 4)动态配置实例的属性Java获取反射的三种方法

1.通过new对象实现反射机制

2.通过路径实现反射机制

3.通过类名实现反射机制

常用API

String相关

字符型常量和字符串常量的区别

1. 形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符

2. 含义上: 字符常量相当于一个整形值(ASCII),可以参加表达式运算 字符串常量代表一个地址值(该字

符串在内存中存放位置)

3. 占内存大小 字符常量只占一个字节 字符串常量占若干个字节(至少一个字符结束标志)

什么是字符串常量池?

字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存

储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回

它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

String 是最基本的数据类型吗

不是。Java 中的基本数据类型只有 8 个 :byteshortintlongfloat doublechar

boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引

入的枚举类型也算是一种比较特殊的引用类型。

1 public class Student {

2 private int id;

3 String name;

4 protected boolean sex;

5 public float score;

6 }

1 public class Get {

2 //获取反射机制三种方式

3 public static void main(String[] args) throws ClassNotFoundException {

4 //方式一(通过建立对象)

5 Student stu = new Student();

6 Class classobj1 = stu.getClass();

7 System.out.println(classobj1.getName());

8 //方式二(所在通过路径-相对路径)

9 Class classobj2 = Class.forName("fanshe.Student");

10 System.out.println(classobj2.getName());

11 //方式三(通过类名)

12 Class classobj3 = Student.class;

13 System.out.println(classobj3.getName());

14 }

15 }这是很基础的东西,但是很多初学者却容易忽视,Java  8 种基本数据类型中不包括 String,基本数据

类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’,‘之类的,如果要描述一段文

本,就需要用多个

char 类型的变量,也就是一个 char 类型数组,比如你好就是长度为2的数组 char[] chars = {‘’,‘’};

但是使用数组过于麻烦,所以就有了 StringString 底层就是一个 char 类型的数组,只是使用的时候开

发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

String有哪些特性

不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创

建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并

频繁访问时,可以保证数据的一致性。

常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,

会直接返回缓存的引用。

final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。

String为什么是不可变的吗?

简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下图所以:

String真的是不可变的吗?

我觉得如果别人问这个问题的话,回答不可变就可以了。 下面只是给大家看两个有代表性的例子:

1) String不可变但不代表引用不可以变

结果:

解析:

实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内

存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。

2) 通过反射是可以修改所谓的不可变对象

1 /** The value is used for character storage. */

2 private final char value[];

1 String str = "Hello";

2 str = str + " World";

3 System.out.println("str=" + str);

1 str=Hello World

1 // 创建字符串"Hello World", 并赋给引用s

2 String s = "Hello World";

3

4 System.out.println("s = " + s); // Hello World结果:

解析:

用反射可以访问私有成员, 然后反射出String对象中的value属性, 进而改变通过获得的value引用改变

数组的结构。但是一般我们不会这么做,这里只是简单提一下有这个东西。

是否可以继承 String

String 类是 final 类,不可以被继承。

String str="i" String str=new String(“i”)一样吗?不一样,因为内存的分配方式不一样。String

str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存

中。 String s = new String(“xyz”);创建了几个字符串对象两个对象,一个是静态区的"xyz",一个是用

new创建在堆上的对象。

5

6 // 获取String类中的value字段

7 Field valueFieldOfString = String.class.getDeclaredField("value");

8

9 // 改变value属性的访问权限

10 valueFieldOfString.setAccessible(true);

11

12 // 获取s对象上的value属性的值

13 char[] value = (char[]) valueFieldOfString.get(s);

14

15 // 改变value所引用的数组中的第5个字符

16 value[5] = '_';

17

18 System.out.println("s = " + s); // Hello_World

1 s = Hello World

2 s = Hello_World如何将字符串反转?使用 StringBuilder 或者 stringBuffer  reverse() 方法。示例代码:

数组有没有 length()方法?String 有没有 length()方法

数组没有 length()方法 ,有 length 的属性。String  length()方法。 JavaScript中,获得字符串的长度

是通过 length 属性得到的,这一点容易和 Java 混淆。

String 类的常用方法都有那些?

indexOf():返回指定字符的索引。

charAt():返回指定索引处的字符。

replace():字符串替换。

trim():去除字符串两端空白。

split():分割字符串,返回一个分割后的字符串数组。

getBytes():返回字符串的 byte 类型数组。

length():返回字符串长度。

toLowerCase():将字符串转成小写字母。

toUpperCase():将字符串转成大写字符。

substring():截取字符串。

equals():字符串比较。

在使用 HashMap 的时候,用 String  key 有什么好处?

HashMap 内部实现是通过 key  hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以

当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

StringStringBufferStringBuilder的区别是什么?String 为什么是不可变的

可变性

String类中使用字符数组保存字符串,private final char value[],所以 string对象是不可变的。

StringBuilderStringBuffer都继承自

1 String str1 = "hello"; //str1指向静态区

2 String str2 = new String("hello"); //str2指向堆上的对象

3 String str3 = "hello";

4 String str4 = new String("hello");

5 System.out.println(str1.equals(str2)); //true

6 System.out.println(str2.equals(str4)); //true

7 System.out.println(str1 == str3); //true

8 System.out.println(str1 == str2); //false

9 System.out.println(str2 == str4); //false

10 System.out.println(str2 == "hello"); //false

11 str2 = str1;

12 System.out.println(str2 == "hello"); //true

1 // StringBuffer reverse

2 StringBuffer stringBuffer = new StringBuffer();

3 stringBuffer. append("abcdefg");

4 System. out. println(stringBuffer. reverse()); // gfedcba

5 // StringBuilder reverse

6 StringBuilder stringBuilder = new StringBuilder();

7 stringBuilder. append("abcdefg");

8 System. out. println(stringBuilder. reverse()); // gfedcbaAbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这

两种对象都是可变的。线程安全性

String中的对象是不可变的,也就可以理解为常量,线程安全。

AbstractStringBuilderStringBuilderStringBuffer的公共父类,定义了一些字符串的基本操作,如

expandCapacityappendinsertindexOf等公共方法。StringBuffer对方法加了同步锁或者对调用

的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全

的。

性能

每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。

StringBuffer每次都会对StringBuffer对象本身进行操

作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获

10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结

如果要操作少量的数据用 = String 单线程操作字符串缓冲区 下操作大量数据 = StringBuilder 多线程操

作字符串缓冲区 下操作大量数据 = StringBuffer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老了敲不动了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值