java程序员面试笔试宝典-4.4基本类型与运算

4.4.1 java提供了哪些基本数据类型?

java语言提供了8中原始的数据类型

byte,short,int,long,float,double,char,boolean
字节长度:1,2,4,8,4,8,2,1
这些数据类型不是对象,被创建后立即在栈上创建空间
引用类型:类,接口,数组,这类对象在声明时不会被分配内存空间,只是存储了一个内存地址。
此外java语言还提供了原始类型的封装类
(字符类型:Character,布尔类型:Boolean,数值类型:Byte、Short、Integer、Long、Float、Double)

注意:

1)java中的数值类型都是有符号的,不存在无符号的数
2)取值范围固定,不会随硬件环境改变
3)第9中基本类型void,封装类java.lang.void;只是无法直接进行操作

封装类型与原始类型的不同点:

1)原始类型传递时按值传递,封装类型按引用传递
2)用作某个类的实例数据时,默认数据不同:封装类型为null,原始类型与类型有关。

package cn.itcast.demo3;

public class Test3 {
	String s;
	int i;
	float f;
	public static void main(String[] args) {
		Test3 t = new Test3();
		System.out.println(t.s == null);
		System.out.println(t.i);
		System.out.println(t.f);
	}
}

在这里插入图片描述

注意:

1)在java语言中,默认声明的小数是double类型的,故在对float类型的变量进行初始化时需要进行类型转换。

float类型初始化方式:
float f = 1.0f;
float f = (float)1.0;

2)相似的,直接写的整形数字是int类型的

long l = 26012402244L

引申:

1)java语言中,null是什么;在内存中是什么?

null不是一个合法的Object实例,编译器并没有分配内存,仅仅用来标识该引用目前没有指向任何对象。

2)如何理解String x = null;

定义了一个变量x,x中存放的是String引用,此处为null

4.4.2 什么是不可变类?

即创建了这个类的实例后就不允许修改它的值了
例如所有基本类型的包装类,此外String也是不可变类
表面上看是改变了s的值,实际上原来的字符串"Hello"还存在内存中,并没有被改变,只是s指向了地址。

package cn.itcast.demo3;

public class Test4 {
	public static void main(String[] args) {
		String s = "Hello";
		s += " world";
		System.out.println(s);
	}
}

在这里插入图片描述

创建一个不可变类要遵循以下几个步骤:

1)类中所有成员变量被private修饰
2)类中没有写或者修改成员变量的方法;例如setXXX,只提供构造函数,一次生成,永不改变。
3)确保类中所有方法不会被子类覆盖,可以通过把类定义为final或把类中的方法定义为final
4)如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量时,需要通过clone方法来确保类的不可变性。
5)如果有必要,可使用覆盖Object类的equals方法和hashCode方法
在equals方法中,根据对象的属性值来比较两个对象是否相等,并且保证equals方法判断为相等的两个对象的hashCode方法的返回值也相等。
这可以确保这些对象能被正确的放到HashMap或HashSet集合中

注意:

由于类的不可变性,在创建对象时就需要初始化所有成员变量,因此最好提供一个带参数的构造函数来初始化这些成员变量。

package cn.itcast.demo3;

import java.util.Date;

public class TestImmutable {

	public static void main(String[] args) {
		Date d = new Date();
		ImmutableClass immuC = new ImmutableClass(d);
		immuC.printState();
		d.setMonth(5);
		immuC.printState();
	}

}

在这里插入图片描述
Date对象的状态被改变,而ImmutableClass 保存了Date类型对象的引用,当被引用的对象的状态改变时会导致ImmutableClass 对象状态的改变。

package cn.itcast.demo4;

import java.util.Date;
/*
 *  
 *  1)类中所有成员变量被private修饰
	2)类中没有写或者修改成员变量的方法;例如setXXX,只提供构造函数,一次生成,永不改变。
	3)确保类中所有方法不会被子类覆盖,可以通过把类定义为final或把类中的方法定义为final
	4)如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量时,需要通过clone方法来确保类的不可变性。
	5)如果有必要,可使用覆盖Object类的equals方法和hashCode方法
	在equals方法中,根据对象的属性值来比较两个对象是否相等,并且保证equals方法判断为相等的两个对象的hashCode方法的返回值也相等。
	这可以确保这些对象能被正确的放到HashMap或HashSet集合中
 */
public class ImmutableClass {
	private Date d;
	public ImmutableClass(Date d){
		this.d = (Date)d.clone();//解除了引用关系
	}
	public void printState(){
		System.out.println(d);
	}
	public Date getDate(){
		return (Date)d.clone();
	}
}

在这里插入图片描述

使用不可变类的优缺点:

优点:

使用简单,线程安全,节省内存

缺点:

不可变类的对象会因为值得不同而产生新的对象,导致无法预料的问题。

4.4.3 值传递和引用传递的区别

1)值传递:形参与实参有相同的值,不同的存储单元

2)引用传递:形参与实参指向同一块存储单元。

java中,原始数据类型在传递参数时是值传递,而包装类型在传递参数时是引用传递。

在这里插入图片描述

package cn.itcast.demo4;
public class Test {
	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);
	}
}

在这里插入图片描述

说明:
Integer是不可变量,b++之后,此时会创建一个新值为2的Integer赋值给b
引用也是按值传递的。
调用方法ss1.append(“World”)时,会修改ss1所指向的字符串的值
调用ss2==ss1时候,只会修改了局部变量ss2的值,而对s2毫无影响,因此s2的值在调用前后保持不变。

call by value:按值传递
call by reference:按引用传递

在这里插入图片描述

package cn.itcast.demo4;
//在Java类库中,所有基本数据类型的包装类都是不可变类,此外String也是不可变类
public class Test1 {
	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++;//Integer是不可变类,因此没有提供它值的方法,创建一个新值为2的Integer赋值给b,此时b与a其实已经没有任何关系了
		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);
	}
}

在这里插入图片描述

4.4.4 不同数据类型的转换有哪些规则?

java语言中,当参与运算的两个变量的数据类型不同时,就需要进行隐式的数据类型转换,转换的规则为:从低精度向高精度转换。

即优先级满足:byte<short<char<int<long<folat<double

即short类型能自动转换为int,int类型能自动转换为float类型
反之,则需要通过强制类型转换来实现

类型自动转换需要注意:

1)char类型转换为高级类型,会转换为其对应的ASCII码

2)byte,short,char类型的数据在参与运算时会自动转换为int类型,但是当使用“+=”运算时,就不会产生类型的转换。

3)在java语言中,基本数据类型与boolean类型是不能相互转换的。

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

强制类型转换:

当需要从高级数据类型转换为低级数据类型时,就需要进行强制类型转换。
需要注意的是:在进行强制类型转换的时候可能会损失精度。

说明:if条件只能接受boolean类型的值,int类型不能被隐式地转换为boolean类型。在这里插入图片描述

说明:short类型变量占两个字节,a对应的二进制为0000000010000000,由于byte只占一个字节,在强制转换为byte的时候只截取低字节:10000000,10000000是-128的补码,因此b的值为-128.

package cn.itcast.demo4;

public class Test2 {
	public static void main(String[] args) {
		short a = 128;
		byte b = (byte) a;
		System.out.println(a);
		System.out.println(b);
	}
}

在这里插入图片描述

4.4.5 强制类型转换的注意事项有哪些?

例1:错误写法

在这里插入图片描述

例2:正确写法

在这里插入图片描述

而“+=”运算,java编译器会对其进行特殊处理,不会报错

package cn.itcast.demo4;

public class Test2 {
	public static void main(String[] args) {
		short s1 = 1;
		//s1 = (short) (s1 + 1);
		s1 += 1;//"+="为Java语言规定的运算法,Java编译器会对其进行特殊处理
		System.out.println(s1);
	}
}

在这里插入图片描述

4.4.6 运算符优先级是什么?

在这里插入图片描述
在实际使用中,如果不确定运算符的优先级,最好运用()运算符来控制运算顺序

package cn.itcast.demo4;

public class Test2 {
	public static void main(String[] args) {
		byte a = 5;
        int b = 10;
        int c = a>>2+b>>2;//由于"+"的优先级比">>"高,等价于a>>12>>2
        //">>"-右移操作:参与运算的数字为正数,则高位补0;若为负数,高位补1
        //5-为正数,右移最终为0
        System.out.println(c);
        System.out.println(a);
	}
}

在这里插入图片描述

4.4.7 Math类中的round, ceil ,和floor方法的功能各是什么?

1)round方法标识四舍五入

实现原理:在原来数字的基础上增加0.5,然后向下取整

(int)Math.floor(x+0.5)

2) ceil的功能是向上取整,就是取大于a的最小的整数值

注意:
返回值类型并不是int型,而是double型
若a为正数,则把小数入,若a为负数,则 把小数舍。

3)floor方法的功能是向下取整,对操作数取底,取小于a的最大的整数值

返回值类型也是double型
若a为正数,把小数舍,若a为负数,把小数入。

package cn.itcast.demo4;

public class Test2 {
	public static void main(String[] args) {
		float m = 6.4f;
        float n = -6.4f;
        System.out.println("Math.round("+m+")="+Math.round(m));//6
        System.out.println("Math.round("+n+")="+Math.round(n));//-6
        System.out.println("Math.ceil("+m+")="+Math.ceil(m));//7.0
        System.out.println("Math.ceil("+n+")="+Math.ceil(n));//-6.0
        System.out.println("Math.floor("+m+")="+Math.floor(m));//6.0
        System.out.println("Math.floor("+n+")="+Math.floor(n));//-7.0
	}
}

在这里插入图片描述

4.4.8 ++i和i++有什么区别?

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

package cn.itcast.demo4;

public class Test2 {
	public static void main(String[] args) {
		int i = 1;
        System.out.println(i++ + i++);//1+2=3
        System.out.println("i="+i);//3
        System.out.println(i++ + ++i);//3+5=8
        System.out.println("i="+i);//5
        System.out.println(i++ + i++ + i++);//5+6+7=18
        System.out.println("i="+i);//8
	}
}

在这里插入图片描述

4.4.9 如何实现无 符号数的右移操作

>>有符号右移运算符
>>>无符号右移运算符
将参与运算的对象对应的二进制数右移指定位数
不同点:
>>:若参与运算的数为正数,则在高位补0,若为负,则在高位补1
>>>:无论正负,都会在高位补0

注意:

1)在对char,byte,short等类型进行移位操作时,编译器会自动将数值转化为int类型,然后进行操作。
2)int占4bytee(32bit),因此右移的位数超过32时,移位运算没有意义。
所以在java语言中,为了保证移位运算的有效性,使得向右移动的位数不超过32bit,采用了取余操作。
即a>>n 等价于 a>>(n%32)

package cn.itcast.demo4;
/*
 * >>:若参与运算的数为正数,则在高位补0,若为负,则在高位补1
   >>>:无论正负,都会在高位补0
 */
public class Test2 {
	public static void main(String[] args) {
		int i = -4;
        System.out.println("------------int>>:"+i);//4取反+1
        System.out.println("移位前二进制:"+Integer.toBinaryString(i));
        i>>=1;
        System.out.println("移位后二进制:"+Integer.toBinaryString(i));
        System.out.println("------------int>>:"+i);

        i=-4;
        System.out.println("------------int>>>:"+i);
        System.out.println("移位前二进制:"+Integer.toBinaryString(i));
        i>>>=1;
        System.out.println("移位后二进制:"+Integer.toBinaryString(i));
        System.out.println("------------int>>>:"+i);//无论参与运算的数字为正负,高位补0

        short j=-4;
        //byte、char、short类型的数据再参与运算时会自动转换为int类型,但是当使用"+="另说
        //但是当运算结果再复制给short类型变量,只会取其中低位的两个字节
        System.out.println("------------short>>:"+j);
        System.out.println("移位前二进制:"+Integer.toBinaryString(j));
        j>>>=1;
        System.out.println("移位后二进制:"+Integer.toBinaryString(j));
        System.out.println("------------short>>:"+j);

        i = 5;
        System.out.println("------------int>>:"+i);
        System.out.println("移位前二进制:"+Integer.toBinaryString(i));
        i>>=32;//a >> n 等价于 a >> (n%32) 
        //5 >> 32 等价于 5 >> (32%32) = 5 >> 0 = 5
        System.out.println("移位后二进制:"+Integer.toBinaryString(i));
        System.out.println("------------int>>:"+i);
	}
}

------------int>>:-4
移位前二进制:11111111111111111111111111111100
移位后二进制:11111111111111111111111111111110
------------int>>:-2
------------int>>>:-4
移位前二进制:11111111111111111111111111111100
移位后二进制:1111111111111111111111111111110
------------int>>>:2147483646
------------short>>:-4
移位前二进制:11111111111111111111111111111100
移位后二进制:11111111111111111111111111111110
------------short>>:-2
------------int>>:5
移位前二进制:101
移位后二进制:101
------------int>>:5

说明:

对于short来说,由于short占2byte,移位操作时先转换为int,
-4在无符号移位操作在高位补1,当把结果赋值为short类型时,只取其中低位的两个字节。
因此高位补0还是1对运算没有影响。

-4的二进制表示:1111111111111100,
转换为二进制时会以4Byte输出:高位补1:11111111111111111111111111111100
执行无符号右移1位:0111111111111111111111111111110
把运算结果赋值给j时只会取低的两个字节1111111111111110,对应的十进制为-2

引申:"<<“运算符和”>>"运算符有什么异同?

"<<"运算符表示左移,左移n位表示2的n次方
例如一个数
16可以表示为(m<<4)
由于CPU直接支持位运算,因此位运算的效率比乘法高

区别:

与右移运算不同的是,左移运算没有有符号和无符号区别,在左移时,移除高位的同时在低位补0。
以4<<3为例
1)把4转换为二进制:00000000 00000000 00000000 00000100
2)把最高三位移走,同时其他向左移动三位:00000 00000000 00000000 00000100
3)在最低位补3个0:00000 00000000 00000000 00000100 000=32

相同点:

在进行左移时,如果移动的位数超过该类型的最大位数,编译器会对移动的位数取模,
例如对int型移动33位,实际只移动了33%32=1位

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

java语言中,默认使用的是Unicode编码,即每个字符占用两个字节,可以存储中文
虽然String由char组成,但是采用了一种更灵活的方式来存储,即英文占一个字符,中文两个字符。
这种存储方式可以减少所需的存储空间,提高存储效率。

例1:

package cn.itcast.demo5;

public class Test {
	public static void getLen(String str){
		System.out.println(str + "的长度:" + str.length() + "\t所占字节数:" + str.getBytes().length);
	}
	public static void main(String[] args) {
		String s1 = "Hello";
		String s2 = "您好";
		getLen(s1);
		getLen(s2);
	}
}

在这里插入图片描述

例2:判断一个字符串中是否包含中文字符

package cn.itcast.demo5;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test1 {
	public static void judgeChineseCharactor(String str){
		//“\u4e00”和“\u9fa5”是unicode编码
		//并且正好是中文编码的开始和结束的两个值
		//所以这个正则表达式可以用来判断字符串中是否包含中文
		String regEx = "[\u4e00-\u9fa5]";
		//判断是否存在中文字符
		//英文字符:所占字节数和字符串长度相同
		if(str.getBytes().length == str.length()){
			System.out.println("无汉字");
		}else{//如果存在中文字符,找出字符串中的中文字符
			Pattern p = Pattern.compile(regEx);
			Matcher m = p.matcher(str);
			while(m.find()){
				System.out.print(m.group(0) + "");
			}
		}
	}
	public static void main(String[] args) {
		judgeChineseCharactor("Hello World");
		judgeChineseCharactor("Hello 您好");
	}

}

在这里插入图片描述
说明:首先通过字节长度和字符串长度判断字符串中是否包含中文字符,
若包含,则用正则表达式匹配的方式找出字符串中所有的中文字符

常见笔试题

在这里插入图片描述
AD正确
B:不同的编码方式之间是可以转换的,数据库与web页面可以有各自的编码,二者没有必然的关系。
C:Java语言中,char类型默认使用的Unicode编码方式,每个字符占用两个字节
引申:
ResourceBundle:是一个资源处理类,可以经常在国际化应用中使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值