优秀的编程知识分享平台

网站首页 > 技术文章 正文

Java100天冲刺备战大厂面试——基础篇Day2

nanyue 2024-09-20 21:44:34 技术文章 5 ℃

问题汇总

1.JVM/JRE/JDK三者有什么区别?

2.String str = new String(“abc”) 创建了几个字符串对象?

3.深拷贝和浅拷贝区别是什么?

4.==与equals的区别?

5.重写equals()方法为什么一定要重写hashCode()方法?

6.值传递和引用传递的区别的什么?为什么说Java中只有值传递?

7.什么是反射?有哪些实现方式?有哪些应用?

8.简述面向对象设计原则?

9.使用泛型的好处?什么是类型擦除?

10.你知道内部类吗?

1.JVM/JRE/JDK三者有什么区别?

一张图解决

2.String str = new String(“abc”) 创建了几个字符串对象?

答案:1 个或者 2 个。

如果字符串常量池中已经有"abc"存在,这种情况只需要新建1个对象,否则就需要新建2个对象。

当字符串常量池没有 "abc",此时会创建如下两个对象:

一个是字符串字变量 "abc" 所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,此时该实例也是在堆中,字符串常量池只存放引用。

另一个是通过 new String() 创建并初始化的,内容与"abc"相同的实例,也是在堆中。

3.深拷贝和浅拷贝区别是什么?

我们都知道基本数据类型:数据直接存储在栈中;引用数据类型:存储在栈中的是对象的引用地址,真实的对象数据存放在堆内存里。

浅拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变。

深拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象。

深拷贝相比于浅拷贝速度较慢并且花销较大。

4.==与equals的区别?

==比较的是栈中的值,我们知道,对于基本数据类型是存储在栈中,所以对于基本数据类型用==进行比较是直接比较数值,而对于引用类型来说,栈中存放的只是对象的引用地址,真正的对象实例存放在堆中

equals()方法是Object类的方法,在Object类中的equals()方法体内实际上返回的就是使用==进行比较的结果,所以我们通常都会对equals方式自动化重写,使其比较的是对象的内容

5.重写equals()方法为什么一定要重写hashCode()方法?

hashCode通用的约定是无论何时,对同一个对象调用hashCode()都应该产生同样的值

重写 hashcode() 方法的原因,简单的说就是:为了保证是同一个对象,在 equals 比较相同的情况下 hashcode值必定相同

当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则链到后面(如果是链地址法)。

先调用hashCode,唯一则存储,不唯一则再调用equals,结果相同则不再存储,结果不同则散列到其他位置。因为hashCode效率更高(仅为一个int值),比较起来更快。

如果重写equals不重写hashCode会怎样?

由于默认的 hashcode 方法是根据对象的内存地址经哈希算法得来的,两个不同的对象的hashCode一定不一样,那么执行equals,结果为true,HashSet或HashMap的键会放入值相同值的对象。

6.值传递和引用传递的区别的什么?为什么说Java中只有值传递?

值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。

引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的是引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

基本类型作为参数被传递时肯定是值传递;引用类型作为参数被传递时也是值传递,只不过“值”为对应的引用。


7.什么是反射?有哪些实现方式?有哪些应用?

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

实现方式:

1 Class.forName(“类的路径”);当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。

 Class clz = Class.forName("java.lang.String");

2 类名.class。这种方法只适合在编译前就知道操作的 Class。

 Class clz = String.class;

3 对象名.getClass()。

 String str = new String("Hello");
 Class clz = str.getClass();

4,.如果是基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象。

实际应用

第一种:JDBC 的数据库的连接

在JDBC 的操作中,如果要想进行数据库的连接,则必须按照以上的几步完成

通过Class.forName()加载数据库的驱动程序 (通过反射加载,前提是引入相关了Jar包);

通过 DriverManager 类进行数据库的连接,连接的时候要输入数据库的连接地址、用户名、密码;

通过Connection 接口接收连接。

第二种:Spring 框架的使用,最经典的就是xml的配置模式。

Spring 通过 XML 配置模式装载 Bean 的过程:

将程序内所有 XML 或 Properties 配置文件加载入内存中;

Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息;

使用反射机制,根据这个字符串获得某个类的Class实例;

动态配置实例的属性。

Spring这样做的好处是:

不用每一次都要在代码里面去new或者做其他的事情;

以后要改的话直接改配置文件,代码维护起来就很方便了;

有时为了适应某些需求,Java类里面不一定能直接调用另外的方法,可以通过反射机制来实现。

8.简述面向对象设计原则?

1 开闭原则(核心原则):对扩展开放,对修改关闭

2 里式替换原则:继承必须确保父类所拥有的性质在子类中任然成立(子类不要重写父类非抽象方法)

3 依赖倒置原则:面向接口编程,减低耦合性(高层不依赖低层,)象不依赖细节)

4 单一职责原则:控制类的颗粒度大小,将对象解耦,提高其内聚性(管的事不要太多)

5 接口隔离原则:为各个类建立它们需要的专用接口

6 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用(只与你的直接朋友交谈,不跟“陌生人”说话)

7 合成复用原则:尽量先使用组合和聚合等关联关系,其次才考虑继承关系实现

9.使用泛型的好处?什么是类型擦除?

1 类型安全

泛型的主要目标是提高 Java 程序的类型安全

编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常

符合越早出错代价越小原则

2 消除强制类型转换

泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换

所得即所需,这使得代码更加可读,并且减少了出错机会

类型擦除

泛型是一种语法糖,泛型这种语法糖的基本原理是类型擦除。Java中的泛型基本上都是在编译器这个层次来实现的,也就是说:泛型只存在于编译阶段,而不存在于运行阶段。在编译后的 class 文件中,是没有泛型这个概念的。

10.你知道内部类吗?

1.匿名内部类

没有名字的内部类

匿名内部类必须继承一个抽象类或者实现一个接口。

匿名内部类不能定义任何静态成员和静态方法。

当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。

匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

2.局部内部类

定义在方法中的内部类,定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法,创建方式,new 内部类(),注意局部只能在方法里使用

3.成员内部类

成员位置上的非静态类,可以访问外部类所有的变量和方法,创建方式,外部类实例.new 内部类()

4.静态内部类

可以且只能访问外部类的所有静态变量,静态内部类的创建方式,直接new 静态内部类


package java基础;
import java.util.Comparator;
public class OuterClass {
	private int age;
	private String nameString;
	private static int flag = 1;
	public OuterClass () {
		super();
		// TODO Auto-generated constructor stub
	}
	public OuterClass (int age, String nameString) {
		super();
		this.age = age;
		this.nameString = nameString;
	}
	public void testInternalClass() {		
		/**
		 * @author ASUS
		 * 局部内部类
		 */		
		class Duck {
			public void prints() {
				System.out.println(age+"/"+nameString);
			}
		}
		Duck d = new Duck();
		d.prints();
	}
	/**
	 * @author ASUS
	 * 成员内部类
	 */
	class Monkey {
		public void prints() {
			System.out.println(age+"/"+nameString);
		}
	}
	
    /**
	 * @author ASUS
	 * 静态内部类
	 */
	static class Buck{
		public void prints() {
			System.out.println(flag);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Monkey monkey = new OuterClass (12,"Sun wu kon!").new Monkey();
		monkey.prints();
		OuterClass  outerClass = new OuterClass (13,"Sun wu jing!");
		outerClass.testInternalClass();
		System.out.println();
		//匿名内部类
		int result = new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				// TODO Auto-generated method stub
				return o1.compareTo(o2);
			}
		}.compare("a", "b");
		System.out.println(result);
		//静态内部类直接new,不需要外部类实例
		Buck buck = new Buck();
		buck.prints();
	}
}

内部类优点

1 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!

2 内部类不为同一包的其他类所见,具有很好的封装性;

3 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。

4 匿名内部类可以很方便地定义回调。

注意:局部内部类和匿名内部类访问局部变量的时候,变量必须要加上final

《Java100天冲刺备战大厂面试系列》,会持续更新,想了解的朋友可以关注 ,文章有帮助的话可以长按点赞有惊喜!!!文章比较长,大家可以先 收藏转发后看有什么补充可以在下面评论,谢谢大家

最近发表
标签列表