疯狂Java讲义

疯狂Java讲义
本文知识点总结均来自与李刚老师的《疯狂Java讲义第5版》,作者最近买了一本,所以一边学习一边把书中关键的地方记录下来。文中的标题对应书中的标题,因此大家可以对照标题查看书中更详细的内容。有些比较容易理解的章节会省略。

3 数据类型和运算符

3.3 数据类型分类

Java语言是强类型语言,强类型语言包含两方面的意义:1.所有的变量必须先声明后使用;2.指定类型的变量只能接受类型与之匹配的值。
Java支持的数据类型分为两类:

  • 基本类型 :boolean类型和数值类型。数值类型有整数类型和浮点类型。整数类型包括byte、short、int、long、char,浮点类型包括float和double。char代表字符型,实际上字符型也是一种整数类型,相当于无符号整数类型。
  • 引用类型:包括类、接口和数组类型,还有一种特殊的null类型。
    注意:空引用(null)只能被转换成引用类型,不能转换成基本类型,因此不要把一个null值赋给基本数据类型的变量。

3.4基本数据类型

3.4.1 整型

  • byte:8位
  • short:16位
  • int:32位,最常用的整数类型,给出一个整数默认为int类型。
  • long:64位

所有数字在计算机底层都是以二进制形式存在的,原码是直接将一个数值换算成二进制数。但计算机以补码的形式保存所有的整数。补码计算规则:正数的补码和原码完全相同,负数的补码是其反码加1;反码是对原码按位取反,只是最高位(符号位)保持不变。

3.4.2 字符型

字符型通常用于表示单个的字符,必须用(’)括起来。
字符类型值的三种表示形式:

  • 直接通过单个字符来指定字符型值,例如‘A’。
  • 通过转义字符表示特殊字符型值,例如‘\n’、‘\t’。
  • 直接使用Unicode值来表示字符型值,格式‘uXXXX’,其中XXXX代表一个16进制的整数。

Java没有提供表示字符串的基本数据类型,而是通过String类来表示字符串,由于字符串由多个字符组成,因此字符串要使用双引号括起来。

3.4.3 浮点型

Java浮点数表示形式:

  1. 十进制数形式:这种形式就是简单的浮点数,例如6.32.
  2. 科学计数法形式:例6.32e2,只有浮点类型的数值才可以使用科学计数法形式表示。
  • float型:单精度浮点数,占4字节32位,第1位是符号位,接下来的8位表示指数,再接下来的23位表示尾数;
  • double型:双精度浮点数,占8字节64位,第1位是符号位,接下来的11位表示指数,再接下来的52位表示尾数。默认double类型。

Java还提供了三个特殊的浮点数值:正无穷大、负无穷大和非数,用于表示溢出和出错。使用正数除以0得到正无穷大,使用负数除以0得到负无穷大,0.0除以0.0或对于一个负数开方得到一个非数。正无穷大通过Double和Float类的POSITIVE_INFINITY表示;负无穷大通过Double和Float类的NEGATIVE_INFINITY表示;非数通过Double和Float类的NaN表示。
注意: 所有的正无穷大数值都是相等的,所有的负无穷大数值都是相等的,而NaN不与任何数值相等,包括NaN。只有浮点数除以0才可以得到正无穷大或者负无穷大,因为Java语言会自动把和浮点运算的0(整数)当成0.0(浮点数)处理,如果一个整数除以0,会抛出一个异常:ArithmeticExecption:/by zero.

3.4.4 数值中使用下划线分隔

当程序中用到的数值位数特别多是,程序员眼睛容易看花,为了解决这个问题,Java 7 引入了一个新的功能:可以在数值中使用下划线,不管是整数型数值还是浮点型数值,都可以自由的使用下划线分隔。

int binVal = 0B1000_0000_0000_0000_0000_0000_0000_0011;
double pi = 3.14_15_16_92_65_36;

3.4.5 布尔型

Java规范并没有强制指定boolean类型的便利所占用的内存空间。虽然boolean类型的变量或值只要1位即可保存,但由于大部分计算机在分配内存时允许分配的最小内存单元是字节,因此bit大部分时候实际上是占8位。
boolean类型的值或者变量主要用做旗标来进行流程控制,除此之外还可在三目运算符(?:)中使用。

3.4.6 使用var定义变量

为了简化局部变量的声明,从Java10开始支持使用var定义局部变量;var相当于一个动态类型,使用var定义的局部变量的类型由编译器自动推断——定义变量时分配了什么类型的初始值,那该变量就是什么类型。
因此使用var定义局部变量时,必须在定义局部变量的同时指定初始值,否则编译器无法推断该变量的类型。使用var定义局部变量的优缺点:优点在于编码更简洁,不管什么类型的局部变量直接使用var声明即可;其缺点在于:变量类型的可读性降低。
对于以下情况应该避免使用var定义局部变量:

  • 变量的类型不容易判断
  • 局部变量的使用范围很大

3.5 基本类型的类型转换

3.5.1 自动类型转换

Java所有的数值类型变量可以相互变换,如果系统支持把某种基本类型的值直接赋给另一种基本类型的变量,则这种方式称为自动类型转换。当把一个范围小的数值或变量直接赋给另一个表数范围大的变量时,系统可以进行自动类型转换;否则需要强制转换。

char
int
byte
short
long
float
double

不仅如此,当把基本类型的值和字符串值进行连接运算时,基本类型的值将自动类型转换为字符串类型,虽然字符串类型不是基本类型,而是引用类型。因此如果希望把基本类型的值转换为对应的字符串是,可以把基本类型的值和一个空字符串进行连接。

3.5.2 强制类型转换

强制类型转换的语法格式:(targetType)value在通常情况下,字符串不能转换成基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型。例如,把字符串转换成int类型,则可以通过如下代码实现:

String a = "45";
int iValue = Integer.parseInt(a);

3.5.3 表达式类型的自动提升

当一个算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型将发生自动提升。Java定义了如下的自动提升规则:

  • 所以的byte类型、short类型和char类型将被提升到int类型。
  • 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。

3.6 直接量

直接量是指在程序中通过源代码直接给出的值。能指定直接量的通常只有三种类型:基本类型、字符串类型和null类型。Java支持如下8种类型的直接量:int类型、long类型、float类型、double类型、boolean类型、char类型、String类型和null类型。
String类型的直接量不能赋给其他类型的变量,null类型的直接量可以直接赋给任何引用类型的变量。boolean类型的直接量只能赋给boolean类型的变量。
关于字符串直接量:当程序第一次使用某个字符串直接量时,Java通常会用常量池来缓存字符串直接量,如果程序后面的部分需要用到该字符串直接量时,Java会直接使用常量池中的字符串直接量。
由于String类是一个不可变类,因此String对象创建出来就不可能被改变,因此无需担心共享String对象会导致混乱。
常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据,它包括关于类、方法、接口中的常量也包括字符串直接量。

3.7 运算符

3.7.1 算术运算符

/:除法运算符,两个操作数都是整数类型,则计算结果是整数,但除数不可以为0;如果有一个或者两个都是浮点数,计算结果也是浮点数,此时允许除数为0或者0.0,得到结果为正无穷大和或者负无穷大
%:求余运算符,果有一个或者两个都是浮点数,计算结果也是浮点数,此时允许除数为0或者0.0,得到结果为非数
++:自加。单目运算符,只能操作一个数。只能操作单个数值型的变量,不能操作常量或者表达式。++在左边,先操作数加1,然后把操作数放入表达式中运算;++放在右边,先把操作数放入表达式中运算,然后才把操作数加1.

3.7.3 位运算符

一般来说,位运算符只能操作整数类型的变量或值。Java支持的位运算符有如下7个:
&:按位与
|:按位或
~:按位非
^:按位异或
<<:左移运算符,将操作数的二进制码整体左移指定位数,左移以后右边空出来的位以0补充。
>>:右移运算符,把第一个操作数的二进制码右移指定位数后,左边空出来的位以原来的符号位填充,正数补0,负数补1.
>>>:无符号右移运算符,把第一个操作数的二进制码右移指定位数后,左边空出来的位以0补充。
移位运算时遵循如下规则:

  • 对于低于int类型的操作数总是先自动类型转换为int类型后再移位。
  • 对于int类型的整数移位a>>b,当b>32时,系统先用b对32求余,因为int类型只有32位,得到的结果才是真正移位的位数。
  • 对于long类型的整数移位a>>b,当b>64时,系统先用b对64求余,因为int类型是64位,得到的结果才是真正移位的位数。

3.7.5 比较运算符

==:如果 比较的两个操作数都是数值类型,即使数据类型不相同,只要它们的值相等,也都返回true。例如97=='a' 返回true.如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而这两个引用必须指向同一个对象才会返回true。Java也支持两个boolean类型的值进行比较,例如true==false。

3.7.6 逻辑运算符

逻辑运算符主要有以下6个:&&、&、||、|、!、^。
&&与&区别:后者是不短路与。
||与|区别:后者是不短路或。

int a = 5;
int b = 10;
if(a > 4 | b++ > 10){    
    System.out.println("a的值是:" + a + ", b的值是:" + b);
}
int c = 5;
int d = 10;
if(c > 4 || d++ > 10){    
    System.out.println("c的值是:" + c + ", d的值是:" + d);
}

输出结果为:

3.7.7 三目运算符

(expression)? if-true-statement:if-false-statement;
运算规则:先对逻辑表达式expression求值,如果逻辑表达式返回true,则返回第二个操作数的值,如果逻辑表达式返回false,则返回第三个操作数的值。

4 控制流程与数组

4.2 分支结构

Java提供了两种常见的分支控制结构;if语句和switch语句,其中if语句使用布尔表达式或布尔值作为分支条件来进行分支控制,而switch语句则用于对多个整型值进行匹配,从而实现分支控制。
swotch语句由一个控制表达式和多个case标签组成,和if语句不同的是,switch语句后面的控制表达式的数据类型只能是byte、short、int、char四种类型,枚举类型和java.lang.String类型,不能是Boolean类型。

4.3 循环结构

循环语句可能包含 一下四个部分:

  • 初始化语句
  • 循环条件
  • 循环体
  • 迭代语句:这个部分在一次循环体执行结束后,对循环条件求值之前执行,通常用于控制循环条件中的变量,使得循环在合适的时候结束。

do while与while区别:while循环是先判断循环条件,如果条件为真则执行循环体;而do while循环则先执行循环体,然后才判断循环条件,如果循环条件为真,则执行下一次循环,否则终止循环。do while循环的循环条件后必须有一个分号,这个分号表示循环结束。
for循环:对于for循环而言,循环条件总比循环体要多执行一次,因为最后一次执行循环条件返回false,将不再执行循环体。for循环限制性初始化语句,并且置再循环开始前执行一次,每次循环体之前,先计算循环条件的值,如果循环条件返回true,则执行循环体,循环体执行结束后执行循环迭代语句。for循环的循环迭代语句并没有与循环体放在一起,因此即使在执行循环体时遇到continue语句技术本次循环,循环迭代语句也一样会得到执行。

4.4 控制循环结构

1.使用break结束循环:break用于完全结束一个循环,跳出循环体。break语句不仅可以结束其所在的循环,还可以直接结束其外层循环。此时需要在break后紧跟一个标签,这个标签用于标识一个外层循环。
2.使用continue忽略本次循环剩下的语句。continue的功能只是忽略本次循环剩下的语句,接着开始下一次循环,并不会终止循环;continue后也可以紧跟一个标签,用于直接跳过标签所标识循环的剩下语句,重新开始下一次循环。
3.使用return结束方法:return关键字并不是专门用于结束循环的,而功能时结束一个方法。

4.5 数组类型

数组也是一种数据类型,它本身时一种引用类型。在一个数组中,数组元素的类型时唯一的,即一个数组里只能存储一种数据类型的数据。
数组的初始化:所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初值。一单位数组的每个数组元素分配了内存空间,每个内存空间的内容局势该数组元素的值,即使这个内存空间存储的内容是空,这个空也是一个值(null)。
数组的初始化有两种方式:

  • 静态初始化:初始化时由程序员显示指定每个数组元素的初始值,有系统决定数组长度。
  • 动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。

foreach循环:这种循环遍历数组和集合更加简洁。使用其遍历数组和集合时,无须获得数组和集合长度,无须根据索引来访问数组元素和集合元素,foreach循环自动遍历数组和集合的每个元素。
例如:

public class ForEachTest {
    public static void main(String[] args) {
        String[] books = {"轻量级java EE企业应用实战",
        "疯狂java讲义",
        "疯狂Android讲义"};
        for (String book : books)
        {
            System.out.println(book);
        }
    }
}

4.6 深入数组

数组元素和数组变量在内存里是分开开存放的。引用变量是访问真实对象的根本方式。实际的数组对象被存储在堆内存中;如果引用该数组对象的数组引用变量是一个局部变量,那么,它被存储在栈内存中。
**注意:**当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁;因此在所有的方法中定义的局部变量都是放在栈内存中的。在程序创建一个对象时,这个对象被保存到运行时数据区中,以便反复利用,这个运行时数据区就是堆内存。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候回收它。

class Person{
    public int age;
    public double height;
    public void info()
    {
        System.out.println("我的年龄是:" + age + ",我的身高是:" + height );
    }
}

public class ReferenceArrayTest {
    public static void main(String[] args) {
        Person[] Student;
        Student = new Person[2];
        Person zhang = new Person();
        zhang.age = 15;
        zhang.height = 167;

        Person lee = new Person();
        lee.age = 16;
        lee.height = 165;
        Student[0] = zhang;
        Student[1] = lee;
        lee.info();
        Student[1].info();

    }
}

4.6.4 没有多维数组

如果从数组底层的运行机制上来看没有多维数组,java语言里的数组类型是引用类型,数组变量其实是一个引用,这个引用指向真实的数组内存 ,数组元素的类型也可以是引用,如果数组元素的引用再次指向真实的数组内存,这种情形看上去很像多维数组。
type[][] arrName; java采用前面的语法格式来定义二维数组,但它的实质还是一维数组,只是数组元素也是引用,数组元素里保存的引用指向一维数组。
下面程序示范了如何把二维数组当成一维数组出理。

public class TwoDimensionTest {
    public static void main(String[] args) {
        int[][] a;
        a = new int[4][];
        //把a当成一维数组,遍历a中的每个数组元素
        for (int i = 0, len = a.length; i < len; i++)
        {
            System.out.println(a[i]);
        }
        //初始化a数组的第一个元素
        a[0] = new int[2];
        a[0][1] = 6;
        for (int i = 0, len = a[0].length; i < len; i++)
        {
            System.out.println(a[0][i]);
        }
    }
}

4.6.5 操作数组的工具类:Arrays

下面程序示范了Arrays类的用法

public class ArrayTest {
    public static void main(String[] args) {
        int[] a1 = new int[]{3, 4, 5, 6};
        int[] a2 = new int[]{3, 4, 5, 6};
        System.out.println("a1数组和a2数组是否相等:" + Arrays.equals(a1, a2));

        int[] b = Arrays.copyOf(a1, 6);
        System.out.println("a1数组和b数组是否相等:" + Arrays.equals(a1, b));
        System.out.println("b数组元素为:" + Arrays.toString(b));
        //将b数组的第三个元素到第五个元素(不包括)赋值为1
        Arrays.fill(b, 2, 4, 1);
        System.out.println("b数组元素为:" + Arrays.toString(b));
        //对数组进行排序
        Arrays.sort(b);
        System.out.println("b数组元素为:" +Arrays.toString(b));

    }
}

运行结果如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值