java面试 csdn(一天十道Java面试题—-第一天(面向对象——-》ArrayList和LinkedList))
这里是参考B站上的大佬做的面试题笔记 。大家也可以去看视频讲解!!!
1 、面向对象
1.1 、 什么是面向对象?
对比面向过程 、是两种不同的处理问题的角度
面向过程更注重事情的没一个步骤及顺序 ,面向对象更注重事情有哪些参与者(对象) ,及各自需要做什么 。例如:洗衣机洗衣服
面向过程会将任务拆解成一系列的步骤(函数),1 、打开洗衣机---->2 、放衣服------>3 、放洗衣粉---->4 、清洗------>5 、烘干 面向对象会拆出人和洗衣机两个对象:人:打开洗衣机 ,放衣服 ,放洗衣粉 。洗衣机:清洗 、烘干从以上例子可以看出:面向过程比较直观高效 ,而面向对象更易于复用 ,扩展和维护 。
1.2 、面向对象
封装
封装的意义 ,在于明确标识出允许外部使用的所有成员函数和数据项 ,内部细节对外部调用透明 ,外部调用无需修改或者关心内部实现 。
1 、javabean的属性私有 ,提供get/set对外访问 ,因为属性的赋值或者获取逻辑只能由javabean本身决定,而不能由外部胡乱修改 。
2 、orm框架:操作数据库 ,我们不需要关心链接时如何建立的 ,sql时如何执行的,只需要引入mybatis ,调方法即可 。
继承
继承基类的方法 ,并做出自己的改变或扩展 子类共性的方法或者属性直接使用父类的,而不需要自己再定义 ,只需扩展自己个性化的多态
基于对象所属类的不同 ,外部对同一个方法的调用 ,实际执行的逻辑不同 。 继承 ,方法重写 ,父类引用指向子类对象 父类类型 变量名 = new 子类对象; 变量名.方法名();无法调用子类特有的功能
2、JDK 、JRE 、JVM区别和联系
JDK:
java Develpment Kit java 开发工具JRE:
java Runtime Environment java 运行时环境JVM:
java Virtual Machine java 虚拟机3、==和equals
对比的时栈中的值 ,基本数据类型是变量值 ,引用类型是堆中内存对象的地址 equals:object中默认也是采用比较 ,通常会重写 String类中被复写的equals()方法其实是比较两个字符串的内容举例
@Test void test(){ String str1 = "hello"; String str2 = new String("hello"); String str3 = str2;//引用传递 System.out.println("123"); System.out.println("(str1 == str2):"+(str1 == str2));//false System.out.println("(str1 == str3):"+(str1 == str3));//false System.out.println("(str2 == str3):"+(str2 == str3));//true System.out.println("str1.equals(str2):"+str1.equals(str2));//true System.out.println("str1.equals(str3):"+str1.equals(str3));//true System.out.println("str2.equals(str3):"+str2.equals(str3));//true }4 、final
4.1 、简述final作用 最终的
修饰类:表示类不可被继承 修饰方法:表示方法不可被子类覆盖 ,但是可以重载 修饰变量:表示变量一旦被赋值就不可以更改它的值 。(1) 、 修饰成员变量
如果final修饰的类变量,只能在静态初始化块中指定初始值或声明该类变量时指定初始值 如果final修饰的是成员变量 ,可以在非静态初始化块 ,声明该变量或者构造器中执行初始值。(2) 、修饰局部变量
系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化 ,因此使用final修饰局部变量时 ,即可以在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值 ,而在后面的代码中对final变量赋初值(仅一次)
(3) 、修饰基本类型数据和引用类型数据
如果是基本数据类型的变量 ,则其数值一旦在初始化之后便不能更改 如果是引用类型的变量 ,则在对其初始化之后便不能再让其指向另一个对象 ,但是引用的值是可以改变的4.2 、为什么局部内部类和匿名内部类只能访问局部final变量?
首先需要知道的一点是:内部类和外部类是处于同一个级别的 ,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁 。
这里就会产生问题:当外部类的方法结束时 ,局部变量就会被销毁 ,但是内部类对象可能还存在(只有没有人再引用它时 ,才会死亡) 。这里就出现了一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题 ,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后 ,内部类仍可以访问它 ,实际访问的是局部变量的copy,这样好像就延长了局部变量的生命周期 。
将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的 ,也就是如果我们再内部类中修改了成员变量 ,方法中的局部变量也得跟着改变,怎样解决问题呢?
就将局部变量设置为final 、对它初始化之后 ,我就不让你再去修改这个变量 ,就保证了内部类的成员变量和方法的局部变量的一致性 ,这实际上也是一种妥协 ,使得局部变量与内部类内建立的拷贝保持一致性 。
5 、String 、StringBuffer、StringBuilder区别及使用场景
String是final修饰的 、不可变 、每次操作都会产生新的String对象 StringBuffer和StringBuilder都是在原对象上操作 StringBuffer是线程安全的 ,StringBuilder线程不安去的 StringBuffer方法都是synchronized修饰的性能:StringBuilder > StringBuffer > String
场景:经常需要改变字符串内容时使用后面两个
优先使用StringBuilder ,多线程使用共享变量时使用StringBuffer6、重载和重写的区别
重载:发生在同一个类中 ,方法名必须相同 ,参数类型不同 ,顺序不同,方法的返回值和访问修饰符可以不同 ,发生在编译时期。 重写:发生在父子类中 ,方法名,参数列表必须相同 ,返回值范围小于等于父类 ,抛出的异常范围小于等于父类 。访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法 。7 、接口和抽象类
抽象类可以存在普通成员函数,而接口中只能存在public abstract方法 抽象类中的成员变量可以是各种类型的 ,而接口中的成员变量只能是public static final 类型的 抽象类只能继承一个 ,接口可以实现多个 。接口的设计目的 ,是对类的行为进行约束(更准确的说是一种“有 ”约束 ,因为接口不能规定类不可以有什么行为) ,也就是提供一种机制 ,可以强制要求不同的类具有相同的行为 ,它只约束了行为的有无 ,但不对如何实现行为进行限制 。
而抽象类的设计目的 ,是代码复用 。当不同的类具有某些相同的行为(记为行为集合),且其中一部分行为的实现方式一致时(A的非真子集 ,记为B)可以让这些类都派生与一个抽象类 ,在这个抽象类中实现了B,避免让所有的子类来实现B ,这就达到了代码复用的目的 。而A减去B的部分 ,留给各个子类自己实现,正是因为A-B在这里没有实现 ,所以抽象类不允许实例化出来(否则当调用到A-B时 ,无法执行) 。
抽象类是对类本质的抽象 ,表达的是is-a的关系 ,比如:BMW is a car 。抽象类包含并实现子类的通用特性 ,将子类存在差异化的特性进行抽象 ,交由子类去实现 。
而接口是对行为的抽象 ,表达的是like a的关系 ,比如:bird like a aircraft(像飞行器一样飞) ,但其本质上 is a bird 。接口的核心是定义行为,至于实现主体是谁 ,是如何实现 ,接口并不关心 。
使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候 ,用接口
抽象类的能力要远超过接口 ,但是,定义抽象类的代价高 ,因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类 ,在这个类中 ,你必须继承或编写出其所有子类的所有共性 。虽然接口在功能上会弱化许多 ,但是它只是针对一个动作的描述 ,而且你可以在一个类中同时实现多个接口 ,在设计阶段会降低难度
8 、List和Set
List:有序、按对象进入的顺序保存对象 ,可重复 ,允许多个Null元素对象 ,可以使用iterator取出所有元素,在逐一遍历 ,还可以使用get(int index)获取指定下的元素。 Set:无序 、不可重复 、最多允许有一个Null元素对象 ,取元素时只能用iterator接口取得所有的元素,在逐一遍历各个元素 。 **铁汁们 、铁汁们 、铁汁们 、都看到这里了 、动动可爱的小手 、点个赞呗 、鼓励一下 。哈哈哈**9 、hashcode和equals
hashcode介绍
hashcode()的作用是获取哈希码 ,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置 。hashcode()定义在JDK的Object.java中 ,java中的任何类都包含有hashcode()函数 。散列表存储的是键值对(key-value),它的特点是:能根据“键 ”快速的检索出对应的“值 ” 。这其中就利用到了散列码!(可以快速找到所需要的对象)
为什么要有hashcode
以“HashSet如何检查重复 ”为例子来说明为什么要有hashcode:
对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置 ,看该位置是否有值 ,如果没有、HashSet会假设对象没有重复出现 。但是如果发现有值 ,这时会调用equals()方法来检查两个对象是否真的相同 。如果两者相同 ,HashSet就不会让其加入操作成功 。如果不同的话 ,就会重新散列到其他位置 。这样就大大减少了equals的次数 ,相应就大大提高了执行速度 。
如果两个对象相等 ,则hashcode一定也是相同的 。 两个对象相等 ,对两个对象分别调用equals方法都返回true 两个对象有相同的hashcode值 ,它们也不一定是相等的 因此 、equals方法被覆盖过,则hashcode方法也必须被覆盖 hashcode()的默认行为是对堆上的对象产生独特值 ,如果没有重写hashcode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)10 、ArrayList和Linkedlist
ArrayList:
基于动态数组 ,连续内存存储,适合下标访问(随机访问) ,扩容机制:因为数组长度固定 ,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组 ,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素) ,使用尾插法并指定初始容量可以极大提升性能甚至超过LinkedList(需要创建大量的index对象)LinkedList:
基于链表 ,可以存储在分散的内存中 ,适合做数据插入及删除操作 ,不适合查询;需要逐一遍历 ,遍历LinkedList必须使用iterator不能使用for循环 ,因为每次for循环体内通过get(i)取得某一元素时都需要对list重新遍历 ,性能消耗极大。
另外不要试图使用index()等返回元素索引 ,并利用其进行遍历,使用indexof对list进行了遍历 ,当结果为空时会遍历整个列表创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!