知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技

Java基本类型与运算

发表时间:2022-03-25来源:网络

目录

1、Java提供了哪些基本数据类型

以上这些基本类型可以分为如下4种类型:

1.在Java语言中null值是什么?在内存中null是什么?

2.如何理解赋值语句 Stringx=null?

2、什么是不可变类

3、值传递与引用传递有哪些区别

(1)值传递

(2)引用传递

4、不同数据类型的转换有哪些规则

(1)类型自动转换

(2)强制类型转换

5、强制类型转换的注意事项有哪些

6、运算符优先级是什么

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

1)round方法表示四舍五入。

2)ceil方法的功能是向上取整。

3)floor方法的功能是向下取整。

8、++i与i++有什么区别

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

引申:“”运算符有什么异同?

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

1、Java提供了哪些基本数据类型

Java 语言一共提供了8种原始的数据类型(byte,short,int,long,float,double,char,boolean),这些数据类型不是对象,而是Java语言中不同于类的特殊类型,这些基本类型的数据变量在声明之后就会立刻在栈上被分配内存空间。除了这8种基本的数据类型外,其他类型都是引用类型(例如类、接口、数组等),引用类型类似于C++中的引用或指针的概念,它以特殊的方式指向对象实体,这类变量在声明时不会被分配内存空间,只是存储了一个内存地址而已

为Java中的基本数据类型及其描述。

 

以上这些基本类型可以分为如下4种类型:

1)int 长度数据类型:byte(8bit)、short(16bit)、int(32 bit)、long(64 bit)

2)float 长度数据类型:单精度(32bit float)、双精度(64bit double)

3)boolean 类型变量的取值:ture、false。

4)char数据类型:unicode字符(16bit)。

此外,Java语言还提供了对这些原始数据类型的封装类(字符类型Character,布尔类型Boolean,数值类型ByteShortInteger、Long、Float、Double)。需要注意的是,Java中的数值类型都是有符号的,不存在无符号的数,它们的取值范围也是固定的,不会随着硬件环境或者操作系统的改变而改变。除了以上提到的8种基本数据类型以外,在Java语言中,还存在另外一种基本类型void,它也有对应的封装类 java.lang.void,只是无法直接对它进行操作而已。封装类型和原始类型有许多不同点:首先,原始数据类型在传递参数时都是按值传递,而封装类型是按引用传递的。其次,当封装类型和原始类型用作某个类的实例数据时,它们所指定的默认值不同。对象引用实例变量的默认值为null,而原始类型实例变量的默认值与它们的类型有关(例如int默认初始化为0),示例如下:

除了以上需要注意的内容外,在Java语言中,默认声明的小数是double类型的,因此在对float类型的变量进行初始化时需要进行类型转换。float类型的变量有两种初始化方法:float f=1.0f或float f=(float)1.0。与此类似的是,在Java语言中,直接写的整型数字是int类型的,如果在给数据类型为long的变量直接赋值时,int类型的值无法表示一个非常大的数字,因此,在赋值时可以通过如下的方法来赋值:long1=26012402244L。

引申:

1.在Java语言中null值是什么?在内存中null是什么?

null不是一个合法的Object实例,所以编译器并没有为其分配内存,它仅仅用于表明该引用目前没有指向任何对象。其实,与C语言类似,null是将引用变量的值全部置0

2.如何理解赋值语句 Stringx=null?

在Java 语言中,变量被分为两大类型:原始值(primitive)与引用值(reference)。声明为原始类型的变量,其存储的是实际的值。声明为引用类型的变量,存储的是实际对象的地址(指针,引用)。对于赋值语句Stringx=null,它定义了一个变量“x”,x中存放的是String引用,此处为null。

2、什么是不可变类

不可变类(immutable class)是指当创建了这个类的实例后,就不允许修改它的值了,也就是说,一个对象一旦被创建出来,在其整个生命周期中,它的成员变量就不能被修改了。它有点类似于常量(const),即只允许别的程序读,不允许别的程序进行修改。

在Java类库中,所有基本类型的包装类都是不可变类,例如Integer、Float等。此外,String也是不可变类。可能有人会有疑问,既然String是不可变类,为什么还可以写出如下代码来修改String类型的值呢?


表面上看,好像是修改String类型对象s的值。其实不是,Strings=“Hello”语句声明了一个可以指向String类型对象的引用,这个引用的名字为s,它指向了一个字符串常量“Hello”。s+="world"并没有改变s所指向的对象(由于“Hello”是String类型的对象,而String又是不可变量),这句代码运行后,s指向了另外一个String类型的对象,该对象的内容为“Hello world”。原来的那个字符串常量“Hello”还存在于内存中,并没有被改变。

在介绍完不可变类的基本概念后,下面主要介绍如何创建一个不可变类。通常来讲,要创建一个不可变类需要遵循下面4条基本原则

1)类中所有成员变量被private所修饰

2)类中没有写或者修改成员变量的方法,例如setxxx,只提供构造函数,一次生成,永不改变。

3)确保类中所有方法不会被子类覆盖,可以通过把类定义为final或者把类中的方法定义为final来达到这个目的

4)如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量时,需要通过clone方法来确保类的不可变性。

5)如果有必要,可使用覆盖Object类的equals()方法和hashCode()方法。在equals()方法中,根据对象的属性值来比较两个对象是否相等,并且保证用equals()方法判断为相等的两个对象的hashCode()方法的返回值也相等,这可以保证这些对象能被正确地放到HashMapHashSet集合中。

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

下面通过给出一个错误的实现方法与一个正确的实现方法来说明在实现这种类时需要特别注意的问题。首先给出一个错误的实现方法

需要说明的是,由于Date对象的状态是可以被改变的,而ImmutableClass保存了Date类型对象的引用,当被引用的对象的状态改变时会导致ImmutableClass对象状态的改变。

其实,正确的实现方法如下所示:

Java语言中之所以设计有很多不可变类,主要是不可变类具有使用简单、线程安全、节省内存等优点,但凡事有利就有弊,不可变类自然也有其缺点,例如,不可变类的对象会因为值的不同而产生新的对象,从而导致无法预料的问题,所以,切不可滥用这种模式
 

3、值传递与引用传递有哪些区别

方法调用是编程语言中非常重要的一个特性,在方法调用时,通常需要传递一些参数来完成特定的功能。Java 语言提供了两种参数传递的方式:值传递和引用传递

(1)值传递

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

(2)引用传递

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

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

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

按引用传递其实与传递指针类似,是把对象的地址作为参数的,如图所示。
 

为了便于理解,假设1和“Helo”存储的地址分别为0X12345678和0XFFFFFF12。在调用方法testPassParameter时,由于i为基本类型,因此参数是按值传递的,此时会创建一个i的副本,该副本与i有相同的值,把这个副本作为参数赋值给n,作为传递的参数。而StringBuffer由于是一个类,因此按引用传递,传递的是它的引用(传递的是存储“Hello的地址”),如图4-3所示,在testPassParameter内部修改的是n的值,这个值与i是没关系的。但是在修改ss1时,修改的是ss1这个地址指向的字符串,由于形参ssl与实参sl指向的是同一块存储空间,因此修改ss1后,s1指向的字符串也被修改了。

Java中处理8种基本的数据类型用的是值传递,其他所有类型都用的是引用传递,由于这8种基本数据类型的包装类型都是不可变量,因此增加了对“按引用传递”的理解难度。下面给出一个示例来说明:
 

对于上述程序的前两个输出“1”和“2”,不少读者可能会认为,Integer是按值传递的而不是按引用传递的,其实这是一个理解上的误区,上述代码还是按引用传递的,只是由于Integer是不可变类,因此没有提供改变它值的方法,在上例中,在执行完语句b++后,由于Integer是不可变类,因此此时会创建一个新值为2的Integer赋值给b,此时b与a其实已经没有任何关系了。

下面通过程序的后两个输出来加深对“按引用传递”的理解。为了理解后两个输出结果,首先必须理解“引用也是按值传递的”这一要点。为了便于理解,假设sl和s2指向字符串的地址分别为0X12345678和0XFFFFFF12,那么在调用函数changeStringBuffer时,传递s1与s2的引用就可以理解为传递了两个地址0X12345678和0XFFFFFF12,而且这两个地址是按值传递的(即传递了两个值,ss1为0X12345678,ss2为0XFFFFFF12),在调用方法ssl.append("World")时,会修改ssl所指向的字符串的值,因此会修改调用者的sl的值,得到的输出结果为“Hello World”。但是在执行ss2=ss1时,只会修改ss2的值而对s2毫无影响,因此s2的值在调用前后保持不变。为了便于理解,图4-4给出了函数调用的处理过程。
 

从上图中可以看出,在传递参数时相当于传递了两个地址,在调用ss1.append(“World”)时,修改了这个地址所指向字符串的值,而在调用ss2=ss1时,相当于修改了函数changeStringBuffer内部的局部变量s2,这个修改与ssl没关系。

4、不同数据类型的转换有哪些规则

在Java语言中,当参与运算的两个变量的数据类型不同时,就需要进行隐式的数据类型转换,转换的规则为:从低精度向高精度转换,即优先级满足byte”。其中,“>>”被称为有符号右移运算符,“>>>被称为无符号右移运算符它们的功能是将参与运算的对象对应的二进制数右移指定的位数二者的不同点在于“>>”在执行右移操作时,若参与运算的数字为正数,则在高位补0;若为负数,则在高位补1。而“>>>”则不同,无论参与运算的数字为正数或为负数,在执行运算时,都会在高位补0。

此外,需要特别注意的是,在对char、byte、short等类型的数进行移位操作前,编译器都会自动地将数值转化为int类型,然后才进行移位操作。由于int型变量只占4Byte(32bit),因此当右移的位数超过32bit时,移位运算没有任何意义。所以,在Java语言中,为了保证移动位数的有效性,以使右移的位数不超过32bit,采用了取余的操作,即使a>>n等价于a>>
(n%32),示例如下:

需要特别说明的是,对于short类型来说,由于short只占2Byte,在移位操作时会先转换为int类型,虽然在进行无符号右移时会在高位补1,但当把运算结果再赋值给short类型变量时,只会取其中低位的两个字节,因此,高位无论补0还是补1对运算结果无影响。在上例中,-4的二进制表示为1111111111111100(负数以补码格式存储的),在转换为二进制时会以4Byte的方式输出,高位会补1,因此输出为11111111111111111111111111111100,在执行无符号数右移后其二进制变为01111111111111111111111111111110,当把运算结果再复制给i时只会取低位的两个字节,因此,运算结果的二进制表示为:1111111111111110,对应的十进制值为-2,当把-2以二进制形式输出时,同理会以4Byte的方式输出,高位会补1,因此输出为11111111111111111111111111111110。

引申:“”运算符有什么异同?

收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜