Java基础面试题(3)

  •  一、Java中的Math.round(-1.5)等于多少? 

 答案:-1

math类中提供了三个与取整有关的方法:ceil,floor,round,这些方法的作用与它们的英文名称的含义相对应。
例如:

  • ceil的英文意义是天花板,该方法就表示向上取整,math.ceil(11.3)的结果为12,math.ceil(-11.6)的结果为-11;
  • floor的英文是地板,该方法就表示向下取整,math.floor(11.6)的结果是11,math.floor(-11.4)的结果-12;
  • 最难掌握的是round方法,他表示“四舍五入”,算法为math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,math.round(11.5)的结果是12,math.round(-11.5)的结果为-11.

解析:在Java中,Math.round方法是将 double 类型的小数四舍五入后取整的方法,并且它的返回值类型是 long 类型。当小数点后的位数(第一位)大于等于 5 时,该方法返回的值是向上取整;当小数点后的位数小于 5 时,该方法返回的值是向下取整;当小数点后的位数等于 5 时,该方法返回的值是基于偶数取整的结果。

//例子,四舍五入
public class test {
	public static void main(String[] args){
		System.out.println(Math.round(1.3));   //1
		System.out.println(Math.round(1.4));   //1
		System.out.println(Math.round(1.5));   //2
		System.out.println(Math.round(1.6));   //2
		System.out.println(Math.round(1.7));   //2
		System.out.println(Math.round(-1.3));  //-1
		System.out.println(Math.round(-1.4));  //-1
		System.out.println(Math.round(-1.5));  //-1
		System.out.println(Math.round(-1.6));  //-2
		System.out.println(Math.round(-1.7));  //-2
	}
}

二、如何实现对象的克隆?

 在实体类中实现Cloneable接口,并且重写其clone()方法


//实体类
public class Cat implements Cloneable{
    private String name;
//    实体类先实现Cloneable接口,并且重写其clone()方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
    public Cat() {
    }
    public Cat(String name) {
        this.name = name;
    }
}

创建新对象 

public class MyBatisTestApplication {
    public static void main(String[] args) throws CloneNotSupportedException{
        Cat cat = new Cat("chloe");
        Object clone = cat.clone();
        Cat cat2 = (Cat)clone;
        System.out.println(cat2);
        SpringApplication.run(MyBatisTestApplication.class, args);
    }
 
}

三、深克隆和浅克隆的区别?

答案:

浅克隆: 对当前对象进行克隆,并克隆该对象所包含的8种基本数据类型和String类型属性(拷贝一份该对象并重新分配内存,即产生了新的对象);但如果被克隆的对象中包含除8中数据类型和String类型外的其他类型的属性,浅克隆并不会克隆这些属性(即不会为这些属性分配内存,而是引用原来对象中的属性)
深克隆: 深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

对象克隆就是对象的复制操作。分为浅克隆(ShallowClone)和深克隆(DeepClone)

在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制,下面将对两者进行详细介绍。

浅克隆与深克隆的特点

1、被克隆的对象的类应实现 Cloneable 接口,并重写 clone() 方法
2、浅克隆中由于除8中数据类型和String类型外的其他类型的属性不会被克隆,因此当通过新对象对这些属性进行修改时,原对象的属性也会同时改变。而深克隆则已经对这些属性重新分配内存,所以当通过新对象对这些属性进行修改时,原对象的属性不会改变。

四、什么是Java的序列化,如何实现Java的序列化? 

概念: 

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。

序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:
将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。 

五、什么情况下需要序列化?

  对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

       3)对象需要在应用程序内部的不同部分之间进行传递,例如通过消息队列或跨线程通信。

六、Java泛型是如何工作的?什么是类型擦除?

概念:泛型(generics)这个技术是在JDK 5中引入的新特性,它的本质其实是类型参数化,利用泛型可以实现一套代码对多种数据类型的动态处理,保证了更好的代码重用性。并且泛型还提供了编译时对类型安全进行检测的机制,该机制允许我们在编译时就能够检测出非法的类型,提高了代码的安全性。
作用:
  • 泛型可以在编译时对类型进行安全检测,使得所有的强制转换都是自动隐式实现的,保证了类型的安全性;
  • 泛型作为”代码模板“,实现了一套代码对各种类型的套用,提高了代码的可重用性;
  • 避免了不必要的装箱、拆箱操作,提高程序的性能;
使用场景 :
  • 泛型集合:在各种集合中使用泛型,保证集合中元素的类型安全;
  • 泛型方法:在各种方法中使用泛型,保证方法中参数的类型安全;
  • 泛型类:在类的定义时使用泛型,为某些变量和方法定义通用的类型;
  • 泛型接口:在接口定义时使用泛型,为某些常量和方法定义通用的类型;
  • 泛型加反射:泛型也可以结合反射技术,实现在运行时获取传入的实际参数等功能。
泛型类示例: 
//泛型类
public class GenericClass<T> {    
    private T value;   
 
    public GenericClass(T value) { 
         this.value = value; 
    }   
 
    public T getValue() {
        return value;
    }
    public void setValue(T value) {
        this.value = value;
    }
}

//测试类
//TODO 1:泛型类
GenericClass<String> name = new GenericClass<>("mikechen的互联网架构");
System.out.println(name.getValue());
GenericClass<Integer> number = new GenericClass<>(123);
System.out.println(number.getValue());

//运行结果
mikechen的互联网架构
123
 泛型接口示例:
//泛型接口
public interface GenericInterface<T> {
    void show(T value);
    }


public class StringShowImpl implements GenericInterface<String> {
    @Overridepublic
     void show(String value) {
        System.out.println(value);
       }
    }

public class NumberShowImpl implements GenericInterface<Integer> {
    @Overridepublic
     void show(Integer value) {
        System.out.println(value);
        }
    }
泛型方法示例: 
/**  泛型方法   
*     
* @param t 传入泛型的参数     
* @param <T> 泛型的类型     
* @return T 返回值为T类型     
* 说明:     
*   1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。     
*   2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
*   3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。     
*   4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E等形式的参数常用于表示泛型。     
*/    
public <T> T genercMethod(T t){        
        System.out.println(t.getClass());        
        System.out.println(t);        
        return t;    
} 

//main方法
public static void main(String[] args) {    
    GenericsClassDemo<String> genericString  = new GenericsClassDemo("helloGeneric");
 //这里的泛型跟下面调用的泛型方法可以不一样。
    String str = genericString.genercMethod("hello");
//传入的是String类型,返回的也是String类型
    Integer i = genericString.genercMethod(123);
//传入的是Integer类型,返回的也是Integer类型
}

//控制台输出
 class java.lang.String
hello
 class java.lang.Integer
123

什么是类型擦除? 

 概念:类型擦除(Type Erasure)是Java泛型的一种实现机制。它指的是在编译时,Java编译器会将泛型类型参数(如T、E等)替换为其限定类型(bounded type)或者Object类型,并在必要的地方插入类型转换代码。这使得泛型代码能够与没有泛型的Java虚拟机(JVM)兼容。

类型擦除的主要原因是为了向后兼容。在Java 5引入泛型之前,已经存在大量的Java代码和类库。为了让这些代码能够与泛型代码共存,Java设计者选择了类型擦除作为实现泛型的方式。这样,旧的代码可以在不做任何修改的情况下继续工作,而新的泛型代码可以在编译时提供类型安全。

类型擦除的过程如下:

将泛型类型参数替换为限定类型或Object。如果泛型类型参数有限定类型(如<T extends SomeClass>),则替换为限定类型;否则,替换为Object类型。

例如,对于一个泛型类List<T>,编译器会将其转换为一个非泛型类List,其中所有的T类型参数被替换为Object。

在需要的地方插入类型转换代码。由于类型擦除后,泛型类型信息在运行时不再可用,因此编译器需要在合适的地方插入类型转换代码,以确保类型安全。

八、Java中的动态代理是什么?有哪些应用? 

1、代理模式

代理模式是一种设计模式,它通过创建一个代理对象来控制对真实对象的访问。代理对象可以在调用真实对象之前增加额外的逻辑,比如权限验证、记录日志等。代理模式的主要目的是在不修改原有代码的基础上,扩展对象的行为。

2、动态代理原理

动态代理的原理是在运行时动态生成一个代理类,该代理类继承了被代理类的子类,并重写被代理类的方法。在调用被代理类的方法时,代理类会先执行一些额外的逻辑,然后再调用被代理类的方法。通过这种方式,我们可以动态地改变被代理类的行为,而不需要修改原有代码。

动态代理应用场景 
  1. 日志记录:通过动态代理,可以在调用被代理类的方法时增加日志记录的逻辑,以便于追踪和调试。

  2. 事务管理:在调用被代理类的方法之前和之后,可以增加事务管理的逻辑,以确保数据的一致性。

  3. 权限控制:通过动态代理,可以在调用被代理类的方法之前进行权限验证,以控制用户对资源的访问。

参考Java的动态代理详解:原理、实现与应用_Java团长在csdn的博客-CSDN博客  

 

九、Java中反射是什么意思?有哪些应用场景?

概念: Reflection (反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

Java反射是指在运行时动态地获取类的信息,包括类的属性、方法、构造函数等,以及在运行时动态地创建对象、调用方法等。使用Java反射可以在运行时动态地控制类的行为,可以通过反射获取并操作程序中的对象,这样就可以实现一些在编译时无法预测的行为。

得到任何类的内部信息可以: 

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

代码编辑器正是通过反射机制获取到对象所在类的成员方法,进而以UI的方式展示在用户的面前。 

Java反射的使用场景:
  1. 框架开发:Java反射在框架开发中应用非常广泛,可以通过反射机制动态地加载类、创建对象、调用方法等。

  2. 数据库编程:在数据库编程中,使用反射可以动态地获取实体类的属性和方法,从而简化代码的编写。

  3. 单元测试:在单元测试中,可以使用反射来调用私有方法,从而测试代码的完整性和正确性。

  4. 动态代理:Java动态代理机制就是基于反射实现的,可以动态地代理接口,使得我们可以在运行时动态地创建实现某个接口的代理对象。

 

十、反射的优缺点?

优点:
➢ 可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
➢对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值