Java基础知识面试题系列五:41~50题

41.值传递与引用传递有哪些区别

方法调用是编程语言中非常重要的一个特性,在方法调用时,通常需要传递一些参数来完成特定的功能。

Java语言提供了两种参数传递的方式:

  • 值传递
  • 引用传递

值传递:

  • 在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值。

引用传递:

  • 在方法调用中,传递的是对象(也可以看作是对象的地址),这时形参与实参的对象指向同一块存储单元,因此对形参的修改会影响实参的值。

在Java语言中,原始数据类型在传递参数时都是按值传递,而包装类型中传递参数时说按引用传递的。

下面通过一个例子来介绍按值传递和按引用传递的区别:

public class TestPassParameter {
    public static void testPassParameter(StringBuffer ss1,int n){
        ss1.append(" world");  //引用
        n = 8; //值
    }

    public static void main(String[] args) {
        int i =1;
        StringBuffer s1 = new StringBuffer("Hello");
        testPassParameter(s1,i);
        System.out.println(s1);
        System.out.println(i);
    }
}

程序运行结果为:
Hello world
1

  • 按引用传递其实与传递指针类似,是把对象的地址作为参数的。
  • i为基本类型,参数按值传递,会创建一个i的副本,该副本与i有相同的值,把这个副本作为参数赋值给n,作为传递的参数。
  • StringBuffer由于是一个类,因此按引用传递,传递的是它的引用(传递的是存储Hello的地址)
  • 在testPassParameter内部修改的是n的值,这个值与i没关系,但是在修改ss1时,修改的是ss1这个地址指向的字符串,由于形参ss1与实参s1指向的是同一块存储空间,因此修改ss1后,s1指向的字符串也被修改了。

Java中处理8种基本的数据类型用的是值传递,其他所有类型都用的是引用传递,由于这8种基本数据类型的包装类型都是不可变量,因此增加了对按引用传递的理解难度。

下面给出一个示例来说明:

public class TestPassString {
    public static void changeStringBuffer(StringBuffer ss1,StringBuffer ss2){
        ss1.append(" world");
        ss2 = ss1;
    }
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = a;
        b ++ ;
        System.out.println(a);
        System.out.println(b);

        StringBuffer s1 = new StringBuffer("hello");
        StringBuffer s2 = new StringBuffer("hello");
        changeStringBuffer(s1,s2);
        System.out.println(s1);
        System.out.println(s2);
    }
}

程序的输出结果如下所示:
1
2
hello world
hello

  • Inter是按照引用传递的,由于Interger是不可变类,因此没有提供改变它值的方法,
  • 上例中,由于Interger是不可变类,因此会创建一个新值为2的Integer赋值给b,此时b与a其实已经没有任何关系了
  • 通过程序后两个输出来加深对“按引用传输的理解”,首先必须理解“引用也是按值传递的”这一要点。
  • 假设s1和s2指向字符串的地址分别为0X12345678和0XFFFFFF12,那么在调用函数changeStringBuffer时,传递s1与s2的引用就可以理解为传递了两个地址0X12345678和0XFFFFFF12,而且这两个地址是按值传递的
  • 即传递了两个值,ss1为0X12345678,ss2为0XFFFFFF12
  • 在调用方法ss1.append(“World”)时,会修改ss1所指向的字符串的值,因此会修改调用者的s1的值,得到输出结果为Hello World。
  • 但是在执行ss2=ss1时,只会修改ss2的值而对s2毫无影响,因此s2的值在调用前后保持不变。
  • 总结就是在传递参数时相当于传递了两个地址,在调用ss1.append(“world”)时,修改了这个地址所指向字符串的值,而在调用ss2=ss1时,相当于修改了函数changeStringBuffer内部的局部变量ss2,这个修改与ss1没关系。

42.不同数据类型的转换有哪些规则

在Java语言中,当参与运算的两个变量的数据类型不同时,就需要进行隐式的数据类型转换,转换的规则为:

  • 从低精度向高精度转换,即优先级满足byte<short<char<int<long<float<double
  • 例如,不同数据类型的值在进行运算时,short类型数据能够自动转为int类型,int类型数据能够自动转换为float类型。反之,则需要通过强制类型转换来实现。

类型自动转换:
当类型自动转换时,需要注意以下几点:

  • char类型的数据转换为高级类型(如int、long等),会转换为其对应的ASCII码。
  • byte、char、short类型的数据在参与运算时会自动转换为int型,但当使用“+=”运算时,就不会产生类型的转换
  • 在Java语言中,基本数据类型与boolean类型是不能相互转换的。

总结:当有多种类型的数据混合运算时,系统会先自动地将所有数据转换成容量最大的那一种数据类型,然后再进行计算。

强制类型转换:
当需要从高级数据类型转换为低级数据类型时,就需要进行强制类型转换。

43.强制类型转换的注意事项有哪些

  • Java语言中涉及byte、short和char类型的运算时,首先会把这些类型的变量值强制转换为int类型,然后对int类型的值进行计算,最后得到的值也是int类型。因此,如果把两个short类型的值相加,最后得到的结果是int类型。如果把两个byte类型的值相加,最后也会得到一个int类型的值。
  • 如果需要得到short类型的结果,就必须显式地把运算结果转换为short类型,例如对于语句short s1=1;s1=s1+1,由于在运行时会首先将s1转换成int类型,因此s1+1的结果为int类型,这样编译器会报错,所以,正确的写法应该short s1 = 1;s1=(short)(s1+1).
  • 有一种例外情况, “+=”为Java语言规定的运算法,Java编译器会对其进行特殊处理,语句short s1 = 1; s1+=1能够编译通过。

44.Math类中round、ceil和floor方法的功能是什么

  • Math是一个包含了很多数学常量与计算方法的类,位于java.lang包下,能自动导入,而且Math类里边的方法全是静态方法。
  • round方法表示四舍五入。实现原理是在原来数字的基础上先增加0.5然后再向下取整,等同于(int)Math.floor(x+0.5f)。返回值类型为int型,例如Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11.
  • ceil方法的功能是向上取整。对操作数取顶,Math.ceil(a),就是取大于a的最小的整数值。需要注意的是,返回值类型并不是int型,而是double型。若a是整数,则把小数“入”,若a是负数,则把小数“舍”。
  • floor方法的功能是向下取整。对操作数取底。Math.floor(a),取小于a的最大的整数值。返回值类型与ceil方法一样,也是double型。若a是整数,则把小数“舍”。若a是负数,则把小数“入”。

45.++i与i++有什么区别

  • i++是在程序执行完毕后进行自增
  • ++i是在程序开始执行前进行自增

46."<<“运算符与”>>"运算符有什么异同

  • <<运算符表示左移,左移4位。
  • 与右移运算不同的是,左移运算符没有有符号与无符号左移,在左移时,移除高位的同时在低位补0。以4<<3为例,运算步骤如下:
  • 把4转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0100
  • 把该数字的高三位移走,同时其他位向左移动3位
  • 在最低位补3个零,最终结果为0000 0000 0000 0000 0000 0010 0000 0000,对应的十进制数为32

47.char型变量中是否可以存储一个中文汉字

  • Java语言中,默认使用Unicode编码方式,即每个字符占用两个字节,因此可以用来存储中文。
  • String是由char所组成的,但是采用了一种更加灵活的方式来存储,即英文占用一个字符,中文占用两个字符,采用这种存储方式的一个重要作用就是可以减少所需要的存储空间,提高存储效率。
public class GetLength {

    public static void getLen(String str){
        System.out.println(str + "的长度:" +   str.length() + "  所占字节数:" + str.getBytes().length);
    }

    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "你好";
        getLen(s1);
        getLen(s2);
    }
}

程序的运行结果为:
Hello的长度:5 所占字节数:5
你好的长度:2 所占字节数:6

48.字符串创建与存储机制是什么

在Java语言中,字符串起着非常重要的作用,字符串的声明与初始化主要有如下两种情况:

  • 对于String s1 = new String(“abc”)语句与String s2=new String(“abc”)语句,存在两个引用对象s1、s2,两个内容相同的字符串对象“abc”,在内存中地址是不同的。只要用到new总会生成新的对象。
  • 对于String s1 = "abc"语句与String s2="abc"语句,在JVM中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,s1、s2引用的是同一个变量池中的对象。
  • 由于String的实现采用了Flyweight的设计模式,当创建一个字符串变量时,例如String s = “abc”,会首先在字符串常量池中查找是否已经有相同的字符串被定义,其判断依据是String类equals(Object obj)方法的返回值。若已经定义,则直接获取对其的引用,此时不需要创建新的对象。若没有定义,则首先创建这个对象,然后把它加入到字符串池中,再将她的引用返回。
  • 由于String是不可变类,一旦创建好了就不能被修改,因此String对象可以被共享而且不会导致程序的混乱。

示例:

  • String s = “abc”; //把abc放到常量区,在变异时产生
  • String s = “ab” + “c”; //把“ab”+“c”转换为字符串常量“abc”放到常量区中
  • String s = new String(“abc”); //在运行时把“abc”放到堆里面

例如:

  • String s1 = “abc”; //在常量区里面存放了一个“abc”字符串对象
  • String s2 = “abc”; //s2引用常量区中的对象,因此不会创建新的对象
  • String s3 = new String(“abc”); //在堆中创建新的对象
  • String s4 = new String(“abc”); //在堆中又创建一个新的对象

可以把String s = new String(“abc”);语句的执行人为地分解成两个过程。第一个过程是新建对象的过程,即new String(“abc”);第二个过程是赋值的过程,即String s = 。由于第二个过程只是定义了一个名为s的String类型的变量,将一个String类型对象的引用赋值给s,因此在这个过程中不会创建新的对象。

  • 第一个过程中new String(“abc”)会调用String类的构造函数。
public String(String original){
//body
}
  • 在调用这个构造函数时,传入了一个字符串常量,因此语句new String(“abc”)也就等价于“abc”和new String()两个操作了。
  • 若在字符串中不存在“abc”,则会创建一个字符串常量“abc”,并将其添加到字符串池中。
  • 若存在,则不创建,然后new String()会在堆中创建一个新的对象,所以s3与s4指向的是堆中不同的String对象,地址自然不同。

49.对于String类型的变量s,赋值语句s=null与s=""是否相同

  • 对于赋值语句s=null,其中s是一个字符串类型的引用,它不指向任何一个字符串。
  • 而赋值语句s=""中的s是一个字符串类型的引用,它指向另外一个字符串(这个字符串的值为“”,即空字符串),因此两者是不同的。

50.new String(“abc”)创建了几个对象

一个或两个,如果常量池中原来有“abc”,那么只创建一对象。如果常量池中原来没有字符串“abc”,那么就会创建两个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当然,我可以为您介绍一些Java基础知识面试题。以下是一些常见的Java基础知识面试题及其答案: 1. 什么是JavaJava是一种面向对象的编程语言,具有跨平台特性,可以在不同的操作系统上运行。 2. Java的特点有哪些? Java具有以下特点: - 简单易学:Java语法相对简单,与C++相比更易于学习和使用。 - 面向对象Java支持面向对象的编程范式,具有封装、继承和多态等特性。 - 跨平台性:Java通过虚拟机(JVM)实现跨平台,一次编写,到处运行。 - 安全性:Java提供了安全机制,如内存管理、异常处理和安全检查等。 - 多线程:Java支持多线程编程,可以实现并发操作。 3. 什么是面向对象编程? 面向对象编程(OOP)是一种编程范式,将数据和操作数据的方法封装在一起,形成对象对象可以通过定义类来创建,类定义了对象的属性和行为。 4. Java中的基本数据类型有哪些? Java中的基本数据类型包括: - 整数类型:byte、short、int、long - 浮点数类型:float、double - 字符类型:char - 布尔类型:boolean 5. Java中的包是什么? 包(Package)是Java中用于组织类和接口的一种机制。它可以将相关的类和接口放在同一个包中,方便管理和使用。 6. 什么是Java的访问修饰符? Java的访问修饰符用于控制类、方法和变量的访问权限。常用的访问修饰符有public、protected、private和默认(没有修饰符)。 7. Java中的异常处理机制是什么? Java中的异常处理机制通过try-catch-finally语句块来实现。当代码可能抛出异常时,可以使用try块来捕获异常,并在catch块中处理异常。finally块中的代码无论是否发生异常都会执行。 8. 什么是Java的多线程? 多线程是指在一个程序中同时执行多个线程,每个线程都是独立的执行流。Java通过Thread类和Runnable接口来实现多线程编程。 9. Java中的垃圾回收是什么? Java中的垃圾回收是自动内存管理的一种机制,通过垃圾回收器自动释放不再使用的内存。开发人员无需手动释放内存,可以专注于业务逻辑的实现。 10. 什么是Java的反射机制? Java的反射机制是指在运行时动态地获取类的信息并操作类的属性和方法。通过反射机制,可以在运行时创建对象、调用方法和访问属性等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最笨的羊羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值