Java-2020年最全面试题-基础篇(2)【附答案】

一文搞定二叉搜索树、B树、B+树、AVL树、红黑树,
Java-2020年最全面试题-基础篇(1)【附答案】
2020年最全面的计算机专业基础课程和Java项目【附带源码和课件】
Java-2020年最全面试题-基础篇(3)【附答案】
120道BAT数据结构与算法面试题
腾讯校招20道选择题含答案
万字大总结,一文搞定JAVA集合类

三天刷完剑指offer

三天刷完《剑指OFFER编程题》Java版本实现(第一天)
三天刷完《剑指OFFER编程题》Java版本实现(第二天)

三天刷完《剑指OFFER编程题》Java版本实现(第三天)

1、Java中 == 和 equals 和 hashCode 的区别

对于关系操作符 ==

若操作数的类型是基本数据类型,则该关系操作符判断的是左右两边操作数的值是否相等

若操作数的类型是引用数据类型,则该关系操作符判断的是左右两边操作数的内存地址是否相同。也就是说,若此时返回true,则该操作符作用的一定是同一个对象。

对于使用 equals 方法,内部实现分为三个步骤:

  1. 先比较引用是否相同(是否为同一对象),
  2. 再判断类型是否一致(是否为同一类型),
  3. 最后比较内容是否一致

Java 中所有内置的类的 equals 方法的实现步骤均是如此,特别是诸如 Integer,Double 等包装器类。如以下 String 中的 equals 方法实现

// String.java 
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

hashcode是系统用来快速检索对象而使用

equals方法本意是用来判断引用的对象是否一致

重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性

2、 int、char、long各占多少字节数

Java 基本类型占用的字节数

1字节: byte , boolean

2字节: short , char

4字节: int , float

8字节: long , double

注:1字节(byte)=8位(bits)

3、 对 Java 多态的理解

多态是指父类的某个方法被子类重写时,可以产生自己的功能行为,同一个操作作用于不同对象,可以有不同的解释,产生不同的执行结果。

多态的三个必要条件:

继承父类。
重写父类的方法。
父类的引用指向子类对象

然后可以使用结合里氏替换法则进一步的谈理解

里氏替换法则 ---- 所有引用基类的地方必须能透明地使用其子类的对象

子类必须完全实现父类的方法

注意 在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则

注意 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承

子类可以有自己的个性
覆盖或实现父类的方法时输入参数可以被放大
覆写或实现父类的方法时输出结果可以被缩小

在项目中,采用里氏替换原则时,尽量避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就很难调和了, 把子类当做父类使用,子类的“个性”被抹杀——委屈了点;把子类单独作为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离——缺乏类替换的标准

4、 String、StringBuffer、StringBuilder 区别

StringBuffer 和 String 一样都是用来存储字符串的,只不过由于他们内部的实现方式不同,导致他们所使用的范围不同,对于 StringBuffer 而言,他在处理字符串时,若是对其进行修改操作,它并不会产生一个新的字符串对象,所以说在内存使用方面它是优于 String 的

StringBuilder 也是一个可变的字符串对象,他与 StringBuffer 不同之处就在于它是线程不安全的,基于这点,它的速度一般都比 StringBuffer 快

String 字符串的拼接会被 JVM 解析成 StringBuilder 对象拼接,在这种情况下 String 的速度比 StringBuffer 的速度快

str +=”b”等同于str = new StringBuilder(str).append(“b”).toString();

5、 详细解释一下内部类

内部类使得多重继承的解决方案变得更加完整
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响
使用内部类才能实现多重继承

内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
创建内部类对象的时刻并不依赖于外围类对象的创建。
内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
内部类提供了更好的封装,除了该外围类,其他类都不能访问。

当我们在创建某个外围类的内部类对象时,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员

成员内部类
在成员内部类中要注意两点,

成员内部类中不能存在任何 static 的变量和方法
成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类

静态内部类
静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

它的创建是不需要依赖于外围类的。
它不能使用任何外围类的非static成员变量和方法。

6、 抽象类和接口的区别

  1. 默认的方法实现抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现
  2. 实现抽象类使用 extends 关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字 implements 来实现接口。它需要提供接口中所有声明的方法的实现。
  3. 抽象类可以有构造器,而接口不能有构造器
  4. 抽象方法可以有public、protected和default这些修饰符。接口方法默认修饰符是public。你不可以使用其它修饰符。
  5. 抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。
  6. 抽象方法比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
  7. 如果往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类

7、 进程和线程的区别

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。

线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

8、 说明一下public static void main(String args[])这段声明里每个关键字的作用

答案:public: main方法是Java程序运行时调用的第一个方法,因此它必须对Java环境可见。所以可见性设置为pulic.

static: Java平台调用这个方法时不会创建这个类的一个实例,因此这个方法必须声明为static。

void: main方法没有返回值。

String是命令行传进参数的类型,args是指命令行传进的字符串数组。

9、 为什么Java里没有全局变量?

答案:全局变量是全局可见的,Java不支持全局可见的变量,因为:全局变量破坏了引用透明性原则。全局变量导致了命名空间的冲突。

10、如何将String类型转化成Number类型?

答案:Integer类的valueOf方法可以将String转成Number。下面是代码示例:

String numString =1000;
int id=Integer.valueOf(numString).intValue();

1 说一说面向对象的特征

封装,继承,多态和抽象

封装

封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 3 种修饰符: public, private 和 protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。

下面列出了使用封装的一些好处:

通过隐藏对象的属性来保护对象内部的状态。
提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。
禁止对象之间的不良交互,提高模块化继承
继承

给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在不修改类的情况下给现存的类添加新特性。

多态

多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作可以应用到其他类型的值上面。

抽象

抽象是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。

Java 支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的是把类的行为和实现细节分离开。

2 重载和重写的区别

override(重写)

方法名、参数、返回值相同。

子类方法不能缩小父类方法的访问权限。

子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。

存在于父类和子类之间。

方法被定义为final不能被重写。

overload(重载)

参数类型、个数、顺序至少有一个不相同。

不能重载只有返回值不同的方法名。

存在于父类和子类、同类中。

image.png
image.png

3 抽象类和接口有什么区别

接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的

而抽象类是可以有私有方法或私有变量的

实现接口的一定要实现接口里定义的所有方法,

而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。

接口可以实现多重继承,而一个类只能继承一个超类,但可以通过继承多个接口实现多重继承,接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。

4 说说反射的用途及实现

Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有的成员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架

Java反射的主要功能:

确定一个对象的类
取出类的modifiers,数据成员,方法,构造器,和超类.
找出某个接口里定义的常量和方法说明.
创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象).
取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.
在运行时刻调用动态对象的方法.
创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值.
反射的应用很多,很多框架都有用到

spring 的 ioc/di 是反射….

javaBean和jsp之间调用也是反射….

struts的 FormBean 和页面之间…也是通过反射调用….

JDBC 的 classForName()也是反射……

hibernate的 find(Class clazz) 也是反射….

5 int 和 Integer 有什么区别

int 是基本数据类型

Integer是其包装类,注意是一个类。

为什么要提供包装类呢???

一是为了在各种类型间转化,通过各种方法的调用。否则 你无法直接通过变量转化。 比如,现在int要转为String

int a=0;
String result=Integer.toString(a);
1
在java中包装类,比较多的用途是用在于各种数据类型的转化中。

//通过包装类来实现转化的

int num=Integer.valueOf(“12”);
int num2=Integer.parseInt(“12”);
double num3=Double.valueOf(“12.2”);
double num4=Double.parseDouble(“12.2”);
1
//其他的类似。通过基本数据类型的包装来的valueOf和parseXX来实现String转为XX

String a=String.valueOf(“1234”);//这里括号中几乎可以是任何类型
String b=String.valueOf(true);
String c=new Integer(12).toString();//通过包装类的toString()也可以
String d=new Double(2.3).toString();
1
再举例下。比如我现在要用泛型

List nums;

这里<>需要类。如果你用int。它会报错的。

6 说说&和&&的区别

&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。

&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str!= null&& !str.equals(s))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x33 &++y>0) y会增长,If(x33 && ++y>0)不会增长

&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。

7 short s1= 1; s1 = (s1+1是int类型,而等号左边的是short类型,所以需要强转)1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?(没有错)

对于short s1= 1; s1 = s1 + 1;由于s1+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s1时,编译器将报告需要强制转换类型的错误。

对于short s1= 1; s1 += 1;由于 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。

8 静态变量和实例变量的区别?

在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。

在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

9 char型变量中能不能存贮一个中文汉字?为什么?

char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。

10 用最有效率的方法算出2乘以8等於几?

2<< 3,(左移三位)因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2<< 3。

1、 while循环和do循环有什么不同?

while结构在循环的开始判断下一个迭代是否应该继续。do/while结构在循环的结尾来判断是否将继续下一轮迭代。do结构至少会执行一次循环体。

2、 什么是隐式的类型转化?

隐式的类型转化就是简单的一个类型赋值给另一个类型,没有显式的告诉编译器发生了转化。并不是所有的类型都支持隐式的类型转化。

代码示例:

int i = 1000;
long j = i; //Implicit casting

3、 Java的访问修饰符是什么?

访问权限修饰符是表明类成员的访问权限类型的关键字。使用这些关键字来限定程序的方法或者变量的访问权限。它们包含:

public: 所有类都可以访问 protected: 同一个包内以及所有子类都可以访问

private: 只有归属的类才能访问默认: 归属类及相同包下的子类可以访问

4、 静态类型有什么特点?

静态变量是和类绑定到一起的,而不是类的实例对象。每一个实例对象都共享同样一份静态变量。也就是说,一个类的静态变量只有一份,不管它有多少个对象。类变量或者说静态变量是通过static这个关键字来声明的。类变量通常被用作常量。静态变量通常通过类名字来进行访问。当程序运行的时候这个变量就会创建直到程序结束后才会被销毁。类变量的作用域和实例变量是一样的。它的初始值和成员变量也是一样的,当变量没被初始化的时候根据它的数据类型,会有一个默认值。类似的,静态方法是属于类的方法,而不是类对象,它的调用并不作用于类对象,也不需要创建任何的类实例。静态方法本身就是final的,因为重写只会发生在类实例上,静态方法是和类绑定在一起的,不是对象。父类的静态方法会被子类的静态方法屏蔽,只要原来方法没有声明为final。非静态方法不能重写静态方法,也就是说,你不能在子类中把一个静态方法改成实例方法。

非静态变量在每一个对象实例上都有单独的一份值。

5、 声明变量和定义变量有什么不同?

声明变量我们只提供变量的类型和名字,并没有进行初始化。定义包括声明和初始化两个阶段String s;只是变量声明,String s = new String(“bob”); 或者String s = “bob”;是变量定义。

6、对象封装的原则是什么?

封装是将数据及操作数据的代码绑定到一个独立的单元。这样保障了数据的安全,防止外部代码的错误使用。对象允许程序和数据进行封装,以减少潜在的干涉。对封装的另一个理解是作为数据及代码的保护层,防止保护层外代码的随意访问。

7、 数值提升是什么?

数值提升是指数据从一个较小的数据类型转换成为一个更大的数据类型,以便进行整型或者浮点型运算。在数值提升的过程中,byte,char,short值会被转化成int类型。需要的时候int类型也可能被提升成long。long和float则有可能会被转换成double类型。

8、静态变量在什么时候加载?编译期还是运行期?静态代码块加载的时机呢?

当类加载器将类加载到JVM中的时候就会创建静态变量,这跟对象是否创建无关。静态变量加载的时候就会分配内存空间。静态代码块的代码只会在类第一次初始化的时候执行一次。一个类可以有多个静态代码块,它并不是类的成员,也没有返回值,并且不能直接调用。静态代码块不能包含this或者super,它们通常被用初始化静态变量。

9、 什么是数据的封装?

数据封装的一种方式是在类中创建set和get方法来访问对象的数据变量。一般来说变量是private的,而get和set方法是public的。封装还可以用来在存储数据时进行数据验证,或者对数据进行计算,或者用作自省(比如在struts中使用javabean)。把数据和功能封装到一个独立的结构中称为数据封装。封装其实就是把数据和关联的操作方法封装到一个独立的单元中,这样使用关联的这些方法才能对数据进行访问操作。封装提供的是数据安全性,它其实就是一种隐藏数据的方式。

10、 如果不借助中间变量交换两个变量的值?

先把两个值相加赋值给第一个变量,然后用得到的结果减去第二个变量,赋值给第二个变量。再用第一个变量减去第二个变量,同时赋值给第一个变量。代码如下:

int a=5,b=10;a=a+b; b=a-b; a=a-b;

使用异或操作也可以交换。第一个方法还可能会引起溢出。异或的方法如下:
int a=5,b=10;a=a+b; b=a-b; a=a-b;

int a = 5; int b = 10;
a = a ^ b;
b = a ^ b;
a = a ^ b;

image.png

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页