javaSE面试

自动装箱和自动拆箱

JDK5的新特性

1 //自动装箱 基本类型--引用类型  
2 Integer total = 99;
3 
4 //自动拆箱,引用类型--基本类型
5 int totalprim = total;

int和Integer有什么区别

1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0

a=a+b与a+=b的区别

“+=”是java中的一个运算符,而不是两个,所以在运算时 会进行自动类型转换。所以在编译时没有报错。

a=a+b则必须强转,带来的结果就是精度丢失

在两个变量的数据类型一样时:a+=b 和a=a+b 是没有区别的。

但是当两个变量的数据类型不同时,就需要考虑一下数据类型自动转换的问题了,也就是涉及到精度了。

short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

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

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

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

2 << 3,

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

自增(++)自减(–)运算符

1.作用:
    让变量的值增加(++)1或者减少(--)1
2.使用格式
    (1)写在变量的前面(++a,--a)
    (2)写在变量的后面(a++,a--)
3.使用方式
    (1)单独使用: 不和其它运算一起,自己独占一行
        前++/-- 和 后++/-- 没有任何区别
    (2)混合使用: 和其它操作(赋值,打印)一起使用
        前++/--:     [先++/--,后使用]
        后++/--:     [先使用,后++/--]

== 和 equals 的区别是什么?

基本类型:比较的是值是否相同;

引用类型:比较的是引用是否相同(地址值是否相同);

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。

equals 解读

equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。
首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

class Cat {
     
    public Cat(String name) {
     
        this.name = name;
    }private String name;public String getName() {
     
        return name;
    }public void setName(String name) {
     
        this.name = name;
    }
}
​
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

 public boolean equals(Object obj) {
     
		return (this == obj);
	} 

原来 equals 本质上就是 ==。
那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:
String s1 = new String(“老王”);
String s2 = new String(“老王”);
System.out.println(s1.equals(s2)); // true
同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:

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

原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。

  • 总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

不对,两个对象的 hashCode() 相同,equals() 不一定 true。
代码示例:

String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d",  str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));

// 执行的结果:
// str1:1179395 | str2:1179395	false

代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。

地址值和hash值的区别?

哈希值和地址值是不一样的,哈希值是通过哈希算法散列得来的,而地址值是通过是和物理层面有关,是系统分配的,是不存在相同的,而哈希值是可以通过强制手段设置为相同的,也就是说哈希值是一种逻辑上的确保唯一性,而地址值就是物理上确保唯一性。

Java 中操作字符串都有哪些类?它们之间有什么区别?

字符串是常量;它们的值在创建之后不能更改。

特点:

  1. 字符串不变:字符串的值在创建后不能被更改,所以是线程安全的。
    但凡是感觉它要变化的时候,其实都是产生一个新的字符串。
  2. 因为String对象是不可变的,所以它们可以被共享。
  3. String类的底层采用的是字符数组(就有索引,0到长度-1)。
  • 操作字符串的类有:String、StringBuffer、StringBuilder。

  • String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的
    String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder
    可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

  • StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而
    StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于
    StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

javaSE面试_第1张图片

集合、数组、字符串长度的方法

javaSE面试_第2张图片

String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

String str2 = new String(“ABC”)创建了几个对象

两种说法配合着看,其实是一个意思

至少创建一个对象,也可能两个。因为用到new关键字,肯定会在堆中创建一个str2的String对象,它的value是“ABC”。同时如果这个字符串再java String池里不存在,会在java池里创建这个String对象“ABC”。

  1. 首先在常量池中查找是否存在内容为"abc"字符串对象
  2. 如果不存在则在常量池中创建"abc",并让str引用该对象
  3. 如果存在则直接让str引用该对象

方法重载和方法重写

	壹:方法重载
	
    1.概念:
        在同一个类中(目前),如果多个方法的功能相同,只是参数不同,那么可以让多个方法使用相同的名字,这种现象叫做方法重载
    2.参数不同有哪些情况
        (1)个数不同
        (2)类型不同
        (3)多个类型,顺序不同
    3.方法重载与哪些因素无关
        (1)与参数的名称无关
        (2)与返回值类型无关
        (3)和修饰符无关

贰:方法重写

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。

方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效
果,也称为重写或者复写。声明不变,重新实现。

方法重写的注意事项:

1. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
    public > protected    > 默认(什么都不写) > private

2. 子类方法覆盖父类方法,
    返回值类型、函数名和参数列表都要一模一样
        (最简单方式的方法重写)。

3. 父类private的方法,子类无法继承,不存在重写

4. 子类方法覆盖父类方法,
    返回值类型(子类方法的返回值类型<=父类)

叁:方法重载与方法重写的区别

方法重载(OverLoad):
方法名称相同,参数列表不同

方法重写(Override): 覆盖重写
继承中,子类出现了和父类一模一样的方法
(返回值类型,方法名和参数列表都相同),
方法体{}中的内容不一样

重载:发生在一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值和访问修饰符可以不同,发生在编译时

重写:发生在父子类中,方法名,参数列表必须相同,返回值必须小于等于父类,抛出异常的范围必须小于等于父类,访问修饰符范围必须大于等于父类,父类为private则不能重写

函数时不能以返回值来区分的,返回值时函数运行之后的一个状态。保持调用这与被调用这之间的通信

面向对象

1.面向过程:当要实现一个功能时,需要亲力亲为,处理每个细节
2.面向对象:当要实现一个功能时,不关心具体的实现步骤,只关心结果,找一个具有该功能的类,帮我们做事
3.面向对象的思想
    (1)面向对象是基于面向过程的编程思想.
    (2)面向过程:强调的是每一个功能的步骤
    (3)面向对象:强调的是对象,然后由对象去调用功能

java关键字

static(静态)

1)如果发现,某个数据被该类的所有对象所共同使用,只需要一份,这种数据就需要使用static修饰。

2)被static关键字修饰的数据,和对象无关,依赖于类,内存中只有一份。

3)静态的注意事项

静态的东西,可以使用静态的东西,但是不能使用非静态的东西(静态当中不能使用非静态)
原因:
静态方法由类名调用,目前没有对象,
所以静态方法中不能使用对象中的内容(非静态的)
静态的内容随着类的加载而加载,并进行初始化

静态的(先人),非静态的(后人)

静态的内容什么加载到内存中?
    1.new对象的时候
    2.当使用类中的静态内容的时候

静态方法调用的注意事项:
    - 静态方法可以直接访问类变量和静态方法
    - 静态方法不能直接访问普通成员变量或成员方法
    - 非静态方法可以直接访问静态变量或静态方法
    - 静态方法中,不能使用this关键字
        this代表调用方法的对象
        而静态方法由类名调用,没有对象,就没有this的用法

4)静态代码块

格式:
    static {
        //...
    }
特点:
    1.优先于构造方法执行,唯一执行一次
    2.静态代码块,随着类的加载而加载,而且加载的时候就执行一次
    3.静态代码块仍然属于静态的东西,里面不能使用非静态的内容
作用:
    1.给静态成员赋值
    2.完成项目的初始化动作

final

不可改变。可以用于修饰类、方法和变量。

  • 类:被修饰的类,不能被继承。

  • 方法:被修饰的方法,不能被重写(可以重载)。

  • 变量:final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

  • abstract和final不可以同时使用
    abstract要求子类必须覆盖重写,而被final修饰的类,其子类不可以覆盖重写。

final修饰变量

     1.局部变量
        (1)基本类型: 被final修饰的变量中的具体的数据值是不可改变的
                只能赋值一次,不能进行第二次赋值

 		(2)引用类型:被final修饰的应用变量,变量中的地址值不可改变
            但是该变量所指向的内存空间中的内容可以改变

 2.成员变量(看MyClass类)
        (1)定义未赋值:
            保证所有构造方法中,必须给final修饰的成员变量赋值
            其它的成员方法中,不能修改final修饰的变量的值
        (2)定义并赋值
            保证所有的构造方法和成员方法中,不能修改final修饰的成员变量的值

final关键字有哪些用法

  1. 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,我们必须在声明时或者构造方法中对它赋值;
  2. 用来修饰方法参数,表示在变量的生存期中它的值不能被改变;
  3. 修饰方法,表示该方法无法被重写;
  4. 修饰类,表示该类无法被继承。

继承

向上抽取共性,将共同的内容定义在父类中 共性抽取。

java只支持单继承,不支持多继承,但支持多层继承。

注意:
子类可以使用父类中除了private和构造方法以外的内容

好处:
	1.让类与类之间产生了关系
	2.提高了代码的复用性
	3.是多态的前提

继承中三个重名的成员变量访问特点
1、就近原则
2、this.变量名:本类成员变量
3、super.变量名:父类成员变量

继承中构造方法的访问特点

1.构造方法的名字是与类名一致的。
    所以子类是无法继承父类构造方法的

2.子类继承父类,是为了使用父类的内容,
    所以子类创建对象调用构造方法时,
    必须先调用父类的构造方法,
    完成父类成员的初始化动作,
    子类才可以使用父类的成员,
    super()表示调用父类的空参构造

3.子类的构造方法中如果没有手动给出super调用父类构造,
    编译器默认提供一个super()调用父类的空参构造

4.super调用父类构造,只能写在第一句

5.构造方法可以重载,所以:
    super(...):调用父类带参数的构造方法

类的继承与接口的继承的区别(java当中的继承有什么特点)

接口是常量值和方法定义的集合。接口是一种特殊的抽象类。

java类是单继承的。classB Extends classA

java接口可以多继承。Interface3 Extends Interface0, Interface1, interface……

不允许类多重继承的主要原因是,如果A同时继承B和C,而B和C同时有一个D方法,A如何决定该继承那一个呢?

但接口不存在这样的问题,接口全都是抽象方法继承谁都无所谓,所以接口可以继承多个接口。

注意:

1)一个类如果实现了一个接口,则要实现该接口的所有方法。

2)方法的名字、返回类型、参数必须与接口中完全一致。

3)因为接口的方法默认是public类型的,所以在实现的时候一定要用public来修饰(否则默认为protected类型,缩小了方法的使用范围)。

抽象类

抽象:
不够具体的,说不清楚的,能力你要具有,但是怎么实现,父类不管,由子类自己决定

抽象方法的定义格式:
    修饰符 abstract 返回值类型 方法名称(参数列表...);
    普通的成员方法,去掉{},添加abstract

含有抽象方法的类,必然是一个抽象类

抽象类的定义格式:

修饰符 abstract class 类名 {
    //...
}

接口

接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。

注意:

    1.子类/实现类,必须覆盖重写父类/接口中的所有抽象方法

	2.父类和接口中有重名的抽象方法,只需要覆盖重写一次

	3.多个接口中有重名的默认方法,实现类必须覆盖重写一次

	4.父类中的普通方法和接口中的默认方法重名时,
    优先使用父类的普通方法

	5.多个接口中有重名的静态方法,也没有关系,因为静态方法只能使用接口名称调用

接口中的成员变量

 都是常量,被public static final修饰,可以省略
    接口中常量默认值认为是无效的,必须进行赋值

建议:
    接口中常量的名字,全部大写,单词之间用_隔开

补充:
    接口中的默认方法,实现类可以根据需求进行覆盖重写
    不是强制性的

其他成员特点
接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。

接口中,没有构造方法,不能创建对象。

调用接口中的3类方法(接口和实现类)
静态的内容:
1.要么使用类名调用
2.要么使用接口名调用
default:
1.类中的方法,不能有default关键字
2.接口中的带{}的方法,必须使用default关键字(除静态方法外)

接口和抽象类的区别

  1. 抽象类要被子类继承,接口要被类实现。
  2. 接口可继承接口,并可多继承接口,但类只能单继承
  3. 抽象类可以有具体的方法 和属性, 接口只能有抽象方法和不可变常量

多态

多态: 是指同一行为,具有多个不同表现形式。

前提【重点】

  1. 继承或者实现【二选一】
  2. 方法的重写【意义体现:不重写,无意义】
  3. 父类引用指向子类对象【格式体现】

java中的多态: 对象具有多态的特性

Student类是Person类的子类
学生是一个学生,学生是一个人
学生是一个学生:
Student s1 = new Student();//左侧Student类型,右侧Student对象,不是多态
学生是一个人:
Person p = new Student();// 左侧Person类型,右侧Student对象,是多态

多态调用方法:
    方法跟着对象走
多态中成员的访问特点
        成员变量:====了解====
            编译看左边,运行看左边
            编译和运行都看父类
成员方法:
            编译看左边,运行看右边
            编译看父类,运行看子类

多态的好处和弊端(可以结合多态中成员的访问特点来理解)

不使用多态:
    好处: 可以调用子类特有方法
    弊端: 扩展性差

使用多态:
    好处: 扩展性强
    弊端: 不能调用子类的特有行为

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展 性与便利。

多态的引用类型转换

向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a;

为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子 类特有的方法,必须做向下转型。

3.注意:
向下转型时,如果转后类型和创建对象时的类型不一致,就会报出类型转换异常
类型转换异常:ClassCastException
怎么解决这个问题?

        如果是Dog类型对象,转成Dog类型
        如果是Cat类型对象,转成Cat类型
        但是如何判断?
            Animal a = new 谁();
            谁?

        java中提供了一个运算符?

        boolean flag = 变量名 instanceof 数据类型;
        如果变量属于该数据类型,返回true。
        如果变量不属于该数据类型,返回false。

接口作为方法参数
ArrayList和LinkedList有共同的接口List
所以在定义方法时,使用接口List作为方法参数
传递接口的所有的实现类对象

接口作为方法的参数,可以提高复用性和扩展性

多态表示当同一个操作作用在不同对象时,会有不同的语义,从而产生不同的结果。3+4和“3”+“4”

Java的多态性可以概括成"一个接口,两种方法"分为两种编译时的多态和运行时的多态。编译时的多态主要是指方法的重载(overload),运行时的多态主要是指方法的覆盖(override),接口也是运行时的多态

运行时的多态的三种情况:

  • 1、父类有方法,子类有覆盖方法:编译通过,执行子类方法。

  • 2、父类有方法,子类没覆盖方法:编译通过,执行父类方法(子类继承)。

  • 3、父类没方法,子类有方法:编译失败,无法执行。

方法带final、static、private时是编译时多态,因为可以直接确定调用哪个方法。

内部类

  1. 成员内部类:定义在类中,方法外的类。

在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机 类 Engine ,这时, Engine 就可以使用内部类来描述,定义在成员位置。

访问特点
内部类可以直接访问外部类的成员,包括私有成员。
外部类要访问内部类的成员,必须要建立内部类的对象。

创建内部类对象格式
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();

  1. 匿名内部类

调用一次接口Call中的sing方法
1.定义类,实现接口
2.覆盖重写接口中的抽象方法
3.创建实现类对象
4.实现类对象调用方法

为了调用接口中的sing方法,按照以前的方式,必须4步完成,太麻烦
java提供了一种语法格式,将上面的4步合成一步:匿名内部类对象

匿名内部类对象:
1.作用:
    创建子类/实现类对象的一种快捷方式
2.格式:
    new 抽象父类名/接口名() {
        //覆盖重写所有的抽象方法
    }

    new Call(){
        @Override
        public void sing() {
            System.out.println("鬼哭狼嚎...");
        }
    };
    这可以用父类或者父接口接收,为了可以多次调用方法。

3.格式解释:
    (1) new Call(): 创建对象,调用构造方法,构造方法是编译器指定的,我们不能指定
    (2){}: 是Call接口的实现类的内容,但是实现类的名字不是我们指定的,是编译器指定的
  
4.前提
  匿名内部类必须继承一个父类或者实现一个父接口。

文中部分知识引用自
https://blog.csdn.net/qq_43600458/article/details/102768325

https://blog.csdn.net/xianlvfan2224/article/details/102722298

https://blog.csdn.net/qq_36470686/article/details/83444483?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

https://blog.csdn.net/cillyb/article/details/81611090

你可能感兴趣的:(javaBasic)