备战Java面试【每日十道面试题系列】 --基础篇Day2

2021/7/23 1:06:46

本文主要是介绍备战Java面试【每日十道面试题系列】 --基础篇Day2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

 


因为热爱所以坚持,因为热爱所以等待。熬过漫长无戏可演的日子,终于换来了人生的春天,共勉!!!

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

一张图解决

 2.String str = new String(“abc”) 创建了几个字符串对象?
答案:1 个或者 2 个。

  • 如果字符串常量池中已经有"abc"存在,这种情况只需要新建1个对象,否则就需要新建2个对象。
  • 当字符串常量池没有 "abc",此时会创建如下两个对象:
  • 一个是字符串字变量 "abc" 所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,此时该实例也是在堆中,字符串常量池只存放引用。
  • 另一个是通过 new String() 创建并初始化的,内容与"abc"相同的实例,也是在堆中。

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

  • 我们都知道基本数据类型:数据直接存储在栈中;引用数据类型:存储在栈中的是对象的引用地址,真实的对象数据存放在堆内存里。
  1. 浅拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变。
  2. 深拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象。

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

4.==与equals的区别?

  1. ==比较的是栈中的值,我们知道,对于基本数据类型是存储在栈中,所以对于基本数据类型用==进行比较是直接比较数值,而对于引用类型来说,栈中存放的只是对象的引用地址,真正的对象实例存放在堆中
  2. equals()方法是Object类的方法,在Object类中的equals()方法体内实际上返回的就是使用==进行比较的结果,所以我们通常都会对equals方式自动化重写,使其比较的是对象的内容

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

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

  • 重写 hashcode() 方法的原因,简单的说就是:为了保证是同一个对象,在 equals 比较相同的情况下 hashcode值必定相同
  1. 当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则链到后面(如果是链地址法)。
  2. 先调用hashCode,唯一则存储,不唯一则再调用equals,结果相同则不再存储,结果不同则散列到其他位置。因为hashCode效率更高(仅为一个int值),比较起来更快。
  3. 如果重写equals不重写hashCode会怎样?

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

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

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

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

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 的数据库的连接

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

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

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

  4. 通过Connection 接口接收连接。

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

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

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

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

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

  4. 动态配置实例的属性。

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();
		
	}
	
	
}

内部类优点

  • 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
  • 内部类不为同一包的其他类所见,具有很好的封装性;

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

  • 匿名内部类可以很方便的定义回调。

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



最后:创作不易,喜欢的话请给个赞吧,为了保证内容准确查阅了大量的资料,力求严谨准确,如果你也和我一样备战面试,关注我,持续更新,一起加油吧,给努力的自己点个赞!!!

 

 

参考资料
书籍:
java核心技术、java编程思想
博客:https://blog.csdn.net/weixin_43591980/article/details/117215356
https://blog.csdn.net/weixin_44259720/article/details/88414828
https://blog.csdn.net/qq_36470686/article/details/83444483



这篇关于备战Java面试【每日十道面试题系列】 --基础篇Day2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程