本文已收录专栏
🌲《Java进阶之路》🌲
目录
🌴基本数据类型
🍃01、布尔
🍃02、byte
🍃03、short
🍃04、int
🍃05、long
🍃06、float
🍃07、double
🍃08、char
🌴类型转换
🍃01、强制类型转换
🍃02、自动类型转换
🍃03、什么时候会发生类型转换
🌲引用数据类型
🌲Java 运算符编辑
🍐01、算数运算符
🍐02、关系运算符
🍐 03、位运算符
🍐04、逻辑运算符
🍐05、赋值运算符
🍐06、三元运算符
流程控制语句
🌴基本数据类型
Java 是一种静态类型的编程语言,这意味着所有变量必须在使用之前声明好,也就是必须得先指定变量的类型和名称,Java数据类型分类如下:
一个变量可以是:局部变量、成员变量、静态变量
局部变量使用前必须初始化,否则会使程序不可控制,由于我们经常会忘记使用前初始化,so,基本上所有人都要求在定义的时候就初始化赋值,否则不赋值直接使用,编译器不通过。
当变量是成员变量时,可以不初始化,因为会给默认值。
bit是最小的存储单位,相信只要接触过计算机就应该都知道二进制,二进制的一位就是1比特0/1
通常来说,一个英文字符是一个字节,一个中文字符是两个字节。字节与比特的换算关系是:1 字节 = 8 比特。再往上的单位就是 KB,并不是 1000 字节,因为计算机只认识二进制,因此是 2 的 10 次方,也就是 1024 个字节。
🍃01、布尔
布尔(boolean)仅用于存储两个值:true 和 false,也就是真和假,通常用于条件的判断。代码示例:
boolean flag = true;
🍃02、byte
byte 的取值范围在 -128 和 127 之间,包含 127。最小值为 -128,最大值为 127,默认值为 0。
在网络传输的过程中,为了节省空间,常用字节来作为数据的传输方式。代码示例:
byte a = 10;
byte b = -10;
🍃03、short
short 的取值范围在 -32,768 和 32,767 之间,包含 32,767。最小值为 -32,768,最大值为 32,767,默认值为 0。代码示例:
short s = 10000;
short r = -5000;
🍃04、int
int 的取值范围在 -2,147,483,648(-2 ^ 31)和 2,147,483,647(2 ^ 31 -1)(含)之间,默认值为 0。如果没有特殊需求,整型数据就用 int。代码示例:
int a = 100000;
int b = -200000;
🍃05、long
long 的取值范围在 -9,223,372,036,854,775,808(-2^63) 和 9,223,372,036,854,775,807(2^63 -1)(含)之间,默认值为 0。如果 int 存储不下,就用 long,整型数据就用 int。代码示例:
long a = 100000L;
long b = -200000L;
为了和 int 作区分,long 型变量在声明的时候,末尾要带上大写的“L”。不用小写的“l”,是因为小写的“l”容易和数字“1”混淆。
🍃06、float
float 是单精度的浮点数,遵循 IEEE 754(二进制浮点数算术标准),取值范围是无限的,默认值为 0.0f。float 不适合用于精确的数值,比如说货币。代码示例:
float f1 = 234.5f;
为了和 double 作区分,float 型变量在声明的时候,末尾要带上小写的“f”。不需要使用大写的“F”,是因为小写的“f”很容易辨别。
🍃07、double
double 是双精度的浮点数,遵循 IEEE 754(二进制浮点数算术标准),取值范围也是无限的,默认值为 0.0。double 同样不适合用于精确的数值,比如说货币。代码示例:
double d1 = 12.3
那精确的数值用什么表示呢?最好使用 BigDecimal,它可以表示一个任意大小且精度完全准确的浮点数。针对货币类型的数值,也可以先乘以 100 转成整型进行处理。
Tips:单精度是这样的格式,1 位符号,8 位指数,23 位小数,有效位数为 7 位。
双精度是这样的格式,1 位符号,11 位指数,52 为小数,有效位数为 16 位。
取值范围取决于指数位,计算精度取决于小数位(尾数)。小数位越多,则能表示的数越大,那么计算精度则越高。
一个数由若干位数字组成,其中影响测量精度的数字称作有效数字,也称有效数位。有效数字指科学计算中用以表示一个浮点数精度的那些数字。一般地,指一个用小数形式表示的浮点数中,从第一个非零的数字算起的所有数字。如 1.24 和 0.00124 的有效数字都有 3 位。
🍃08、char
char 可以表示一个 16 位的 Unicode 字符,其值范围在 '\u0000'(0)和 '\uffff'(65,535)(包含)之间。代码示例:
char letterA = 'A';
“char占两个字节主要是因为 Java 使用的是 Unicode 字符集而不是 ASCII 字符集。字符集也可以叫编码,编码不同,实际占用的字节就会不同。”
🌴类型转换
关于类型转换主要分为强制类型转换和自动类型转换,还有一些方法可以转换(后面再具体说)
🍃01、强制类型转换
强转语法就是在需要转换的类型前面加上
(type)variableName
代码示例如下:
public class SimpleTesting {
public static void main(String[] args) {
int value_int = 65;
char value_char = (char) value_int;
System.out.println(value_char);
}
}
A //65在 ASCII 码中对应的字符是A
🍃02、自动类型转换
规则:从小到大 ,低字节向高字节自动提升
顺序:
byte(1字节) – > short(2字节)-- > int(4字节) – > long(8字节) --> float(4字节) – > double(8字节)
char (2字节)-- > int(4字节) – > long(8字节) --> float(4字节) – > double(8字节)
画图分析:
🍃03、什么时候会发生类型转换
答: 赋值 | 运算时 ,两边数据类型不一致时就会发生类型转换
🌲引用数据类型
基本数据类型在作为成员变量和静态变量的时候有默认值,引用数据类型也有的。
String 是最典型的引用数据类型,所以我们就拿 String 类举例,看下面这段代码:
public class LocalRef {
private String a;
static String b;
public static void main(String[] args) {
LocalRef lv = new LocalRef();
System.out.println(lv.a);
System.out.println(b);
}
}
输出结果如下所示:
null
null
null 在 编程语言 中是一个很神奇的存在,在你以后的程序生涯中,见它的次数不会少,尤其是伴随着令人烦恼的“空指针异常open in new window”,也就是所谓的 NullPointerException
。
也就是说,引用数据类型的默认值为 null,包括数组和接口。
你可能会问,为什么数组和接口也是引用数据类型啊?
先来看数组:
public class ArrayDemo {
public static void main(String[] args) {
int [] arrays = {1,2,3};
System.out.println(arrays);
}
}
arrays 是一个 int 类型的数组,对吧?打印结果如下所示:
[I@2d209079
[I
表示数组是 int 类型的,@ 后面是十六进制的 hashCode——这样的打印结果太“人性化”了,一般人表示看不懂!为什么会这样显示呢?查看一下 java.lang.Object
类的 toString()
方法就明白了。
数组虽然没有显式定义成一个类,但它的确是一个对象,继承了祖先类 Object 的所有方法。那为什么数组不单独定义一个类来表示呢?就像字符串 String 类那样呢?
一个合理的解释是 Java 将其隐藏了。假如真的存在一个 Array.java,我们也可以假想它真实的样子,它必须要定义一个容器来存放数组的元素,就像 String 类那样。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
数组内部定义数组?没必要的!
再来看接口:
public class IntefaceDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
System.out.println(list);
}
}
List 是一个非常典型的接口:
public interface List<E> extends Collection<E> {}
而 ArrayList 是 List 接口的一个实现:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}
对于接口类型的引用变量来说,你没法直接 new 一个:
只能 new 一个实现它的类的对象——那自然接口也是引用数据类型了。
来看一下基本数据类型和引用数据类型之间最大的差别。
基本数据类型:
- 1、变量名指向具体的数值。
- 2、基本数据类型存储在栈上。
引用数据类型:
- 1、变量名指向的是存储对象的内存地址,在栈上。
- 2、内存地址指向的对象存储在堆上。
堆是堆(heap),栈是栈(stack),如果看到“堆栈”的话,请不要怀疑自己,那是翻译的错,堆栈也是栈。
堆是在程序运行时在内存中申请的空间(可理解为动态的过程,程序员自己new出来的);切记,不是在编译时;因此,Java 中的对象就放在这里,这样做的好处就是:
当需要一个对象时,只需要通过 new 关键字写一行代码即可,当执行这行代码时,会自动在内存的“堆”区分配空间——这样就很灵活。
栈,能够和处理器(CPU,也就是脑子)直接关联,因此访问速度更快。既然访问速度快,要好好利用啊!Java 就把对象的引用放在栈里。为什么呢?因为引用的使用频率高吗?
不是的,因为 Java 在编译程序时,必须明确的知道存储在栈里的东西的生命周期,否则就没法释放旧的内存来开辟新的内存空间存放引用——空间就那么大。
🌲Java 运算符
🍐01、算数运算符
算术运算符除了最常见的加减乘除,还有一个取余的运算符,用于得到除法运算后的余数。
int a = 10;
int b = 5;
System.out.println(a + b);//15
System.out.println(a - b);//5
System.out.println(a * b);//50
System.out.println(a / b);//2
System.out.println(a % b);//0
b = 3;
System.out.println(a + b);//13
System.out.println(a - b);//7
System.out.println(a * b);//30
System.out.println(a / b);//3
System.out.println(a % b);//1
对于初学者来说,加法(+)、减法(-)、乘法(*)很好理解,但除法(/)和取余(%)会有一点点疑惑。在以往的认知里,10/3 是除不尽的,结果应该是 3.333333...,而不应该是 3。相应的,余数也不应该是 1。这是为什么呢?
因为数字在程序中可以分为两种,一种是整型,一种是浮点型,整型和整型的运算结果就是整型,不会出现浮点型。否则,就会出现浮点型。
🍐02、关系运算符
关系运算符用来比较两个操作数,返回结果为 true 或者 false。
🍐 03、位运算符
public class BitOperator {
public static void main(String[] args) {
int a = 60, b = 13;
System.out.println("a 的二进制:" + Integer.toBinaryString(a)); // 111100
System.out.println("b 的二进制:" + Integer.toBinaryString(b)); // 1101
int c = a & b;
System.out.println("a & b:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = a | b;
System.out.println("a | b:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = a ^ b;
System.out.println("a ^ b:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = ~a;
System.out.println("~a:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = a << 2;
System.out.println("a << 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = a >> 2;
System.out.println("a >> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
c = a >>> 2;
System.out.println("a >>> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
}
}
1)按位左移运算符:
public class LeftShiftOperator {
public static void main(String[] args) {
System.out.println(10<<2);//10*2^2=10*4=40
System.out.println(10<<3);//10*2^3=10*8=80
System.out.println(20<<2);//20*2^2=20*4=80
System.out.println(15<<4);//15*2^4=15*16=240
}
}
10<<2
等于 10 乘以 2 的 2 次方;10<<3
等于 10 乘以 2 的 3 次方。
2)按位右移运算符:
public class RightShiftOperator {
public static void main(String[] args) {
System.out.println(10>>2);//10/2^2=10/4=2
System.out.println(20>>2);//20/2^2=20/4=5
System.out.println(20>>3);//20/2^3=20/8=2
}
}
10>>2
等于 10 除以 2 的 2 次方;20>>2
等于 20 除以 2 的 2 次方。
🍐04、逻辑运算符
逻辑与运算符(&&):多个条件中只要有一个为 false 结果就为 false。
逻辑或运算符(||):多个条件只要有一个为 true 结果就为 true。
public class LogicalOperator {
public static void main(String[] args) {
int a=10;
int b=5;
int c=20;
System.out.println(a<b&&a<c);//false && true = false
System.out.println(a>b||a<c);//true || true = true
}
}
逻辑非运算符(!):用来反转条件的结果,如果条件为 true,则逻辑非运算符将得到 false。
单逻辑与运算符(&):很少用,因为不管第一个条件为 true 还是 false,依然会检查第二个。
单逻辑或运算符(|):也会检查第二个条件。
也就是说,& 和 | 性能不如 && 和 ||,但用法一样:
public class LogicalOperator1 {
public static void main(String[] args) {
int a=10;
int b=5;
int c=20;
System.out.println(a<b&a<c);//false & true = false
System.out.println(a>b|a<c);//true | true = true
}
}
🍐05、赋值运算符
赋值操作符恐怕是 Java 中使用最频繁的操作符了,它就是把操作符右侧的值赋值给左侧的变量。来看示例:
public class AssignmentOperator {
public static void main(String[] args) {
int a=10;
int b=20;
a+=4;//a=a+4 (a=10+4)
b-=4;//b=b-4 (b=20-4)
System.out.println(a);
System.out.println(b);
}
}
不过在进行数值的赋值时,需要小点心,比如说下面这种情况:
编译器之所以提示错误,是因为 = 右侧的算术表达式默认为 int 类型,左侧是 short 类型的时候需要进行强转。
public class AssignmentOperator1 {
public static void main(String[] args) {
short a = 10;
short b = 10;
//a+=b;//a=a+b internally so fine
a = (short)(a + b);
System.out.println(a);
}
}
除此之外,还会有边界问题,比如说,两个非常大的 int 相乘,结果可能就超出了 int 的范围:
public class BigIntMulti {
public static void main(String[] args) {
int a = Integer.MAX_VALUE;
int b = 10000;
int c = a * b;
System.out.println(c); // -10000
}
}
程序输出的结果为 -10000,这个答案很明显不是我们想要的结果,虽然可以通过右侧表达式强转 long 的方法解决:
public class BigIntMulti {
public static void main(String[] args) {
int a = Integer.MAX_VALUE;
int b = 10000;
long c = (long)a * b;
System.out.println(c); // 21474836470000
}
}
但尽量不要这样做,结果非常大的时候,尽量提前使用相应的类型进行赋值。
long a = Integer.MAX_VALUE - 1;
long b = 10000;
long c = a * b;
System.out.println(c); // 21474836460000
🍐06、三元运算符
三元运算符用于替代 if-else,可以使用一行代码完成条件判断的要求。来看示例:
public class TernaryOperator {
public static void main(String[] args) {
int a=2;
int b=5;
int min=(a<b)?a:b;
System.out.println(min);
}
}
如果 ? 前面的条件为 true,则结果为 : 前的值,否则为 : 后的值。这个可以用 if 语句来替代。
流程控制语句
可以直接去看我之前写的C++的,没什么区别