一、类 型
1.范围与转换相关
数据类型 | 关键字 | 内置类 | 范围 | 占字节 | 默认值 |
字节型 | byte | Byte | -27 ~ +27=-128~127 | 1字节: 8bit | 0 |
短整型 | short | Short | -215~+27 | 2字节: 16bit | 0 |
整型 | int | Integer | -231~+231 | 4字节: 32bit | 0 |
长整型 | long | Long | -263 ~ +263 | 8字节: 64bit | 0L |
字符型 | char | Character | JDK1.8中Java的字符采用Unicode6.2编码, JVM采用UTF-16Big Endian。 Unicode范围为‘\u0000’到‘\uffff’, 整数范围是0~65535。 例如,65代表‘A’,97代表‘a’ | 2字节: 16bit | ‘\u0000’ Null |
单精度浮点型 | float | Float | Float.MIN_EXPONENT:-126 ~ Float.MAX_EXPONENT:127 | 4字节: 32bit | 0.0F |
双精度浮点型 | double | Double | Float.MIN_EXPONENT:-1022 ~ Float.MAX_EXPONENT:1023 (浮点数默认为double) | 8字节:64bit | 0.0D |
字符型 | boolean | Boolean | false & ture | 1字节: 8bit | false |
类 | className各类类型的类名 | Null |
2.符号的简要使用
格式控制符与算术运算符
格式控制符 | 表示 | 算术运算符 | 按优先级表示 |
---|---|---|---|
%d | 以十进制格式转出 | . [] () , ; | |
%e %E | 以科学记号浮点数输出 | 单目 | ++,–,~,! |
%o %O | 以八进制整数格式控制 | 乘除 | /,%,*,+,- |
%x %X | 以十六进制整数格式输出 | 位运算 | <<,>> |
%s %S | 以字符串格式符号输出 | 关系符号 | >,<,>=.<=,==,!= |
%c %C | 以字符符号输出 | 逻辑符号 | &,^,|,&&,||,?: |
%b %B | 以boolean型输出 | 赋值符号 | =,+=,-=,/=,*/,%= |
像这类符号可以举出非常多到用时查找即可在此仅仅列出部分
3.进制转换与表示格式
举个例子一目了然 :
int number1 = 12;//十进制
int number2 = 014;//八进制
int number3 = 0xc;//十六进制
//浮点数除用小数表示还可用科学记号法表示
double number4 = 0.00123;
double number5 = 1.23e-3;
//若要表示字符,则需要使用“'”符号
char size = 'M';
char name = '麦克喵';
//对于常量的一种表示方法,为使表示更加清晰
int number7 = 1234_5678;
double PI = 3.141_592_653;
4.使用java.util.Scanner与java.math.BigDecimal标准类
1.使用java.util.Scanner
如果是要在命令提示符模式下取得用户输入,基本上可以使用System.in对象的read()方法,不过这个方法返回int类型。
此时可以通过Scanner来代劳:
import java.util.Scanner;//导入类,以下即可简写
Scanner scan = new Scanner (System.in);//建立Scanner实例
int num = scan.nextInt();//获取输入的下一个整数
Scanner的nextInt()方法会先看看标准输入中有无下一个字符串(以空格或换行符分隔),有的话则尝试剖析为int类型,Scanner对每个基本类型都有对应的next__( )方法,如nextByte()、nextDouble()等,如果是直接取得字符串,则使用next(),如果取得用户输入的整行文字(以换行分隔),则使用nextLine()。
2.使用java.math.BigDecimal()
- 由于Java遵循IEEE754浮点数运算规范,使用分数与指数表示浮点数,如0.75会用1/2+1/4表示,0.875会用1/2+1/4+1/8来表示,而0.1会1/16+1/32+1/256+1/512+1/4096+1/8192无限循环下去,无法精确表示而造成运算误差。所以1.0-0.8d 结果在Java、Python、JavaScript语言中也并非得到0.2。故当需要精确计算时要小心使用浮点数,而且也不要用==来比较浮点数运算结果。
- 由上,为了获得更好的精确度,可以使用BigDecimal标准类,它提供有plus()、subtract()、multiply()、divide()方法进行加减乘除运算,add()加运算,equals()比较两个BigDecimal实质上是否相同。
import java.math.BigDecimal;
BigDecimal operand1 = new BigDecimal("1.0");
BigDecimal operand2 = new BigDecimal("0.8");
BigDecimal operand3 = new BigDecimal("0.2");
BigDecimal num = new BigDecimal("2.0");
BigDecimal result = operand1.subtract(operand2);
if(op1.add(op2).add(op3).equals(num)){
System.out.println("op1、op2、op3的和等于num");
}
4.对象指定与相等性
Java并非完全的面向对象程序语言,在Java中有两大类型系统,即基本类型和类类型 。初学者必须区分=,==运算用于基本类型和类类型的不同。
- 当=用于基本类型时,是将值赋给变量,当==用于基本类型时,是比较两个变量所储值是否相等。
- 当在操作对象时,=是表示指定名称adc参考自某个对象,==是指比较两个名称是否参考自同一个对象。!=恰相反,表示两个对象参考自不同对象。
- 从内存的实际运作方面来看,用于基本类型和对象类型,并无不同,都用作比较两个单元引用是否来自同一个地址。
- 进一步的,若比较不同对象或者相同对象的内容值而不关注对象参考时,所用的操作equals()方法更加合适。
二、类类型
1.自动装箱
使用基本类型是出于效率,但更多时候需要基本类型像对象一样被操作。
使用Long、Integer、Double、Float、Boolean、Byte、Short、Character等类打包器。Wapper将基本类型打包到对象中,特殊的Number类对所有类型进行一般化的自动装箱(多态),示例如下:
int data = 20;
Integer wrapper1 = new Integer(data);//使用new新建打包器对象
int i = 20;
Integer wrapper2 = i;//进一步使用自动装箱功能
Integer wrapper3 = 15;
int wrap3 = wrapper3;//自动拆箱
Double val = wrapper3.doubleValue()/3//操作Integer类的doubleValue方法将打包值以double类型返回
System.out.println(wrapper1.compareTo(wrapper2));//操作打包器方法与另一个对象的值进行比较,相同返回0,小于返回-1,大于返回1
Number num = 2.71828f;//使用一般化Number类
Integer i = 10;
System.out.println(i+10);//i会自动拆箱进行加法运算输出20
System.out.println(i++);//i会先自动拆箱先输出10,再自增运算
2.自动拆箱内幕
自动装拆箱其实是一种编译程序语法糖(Compiler Sugar),通过将一些步骤的操作封装到类中达到简化使用的效果。
引入: 当我们如下操作时程序运行结果会出现不同
Integer i1 = 100;
Integer i2 = 100;
System.out.println((i1 == i2)? "ture":"false");//返回ture
Integer i3 = 200;
Integer i4 = 200;
System.out.println((i3 == i4 )?"ture":"falst");//返回false
代码不过是将100改到200但执行的效果却不同,那么这个自动装箱语法糖究竟干了什么?实际上程序会使用Integer.valueof()来建立Integer实例,调用Integer类中的valueof()方法,源码如下
public static Integer valueof(int i){
if(i>=IntegerCache.low && i<=IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
很明显,通过自动装箱到Integer过程中,判断了一个IntegerCache的范围值,Integer的缓存(Cache),默认为byte的可改范围内(-128~127),在此范围内,若有已分配有同值的实例,新的实例并不会分配新的空间储值,而是直接引用已有实例的空间地址。而在超过此范围时都会重新生成新的实例。
故,在比较类类型的值时,使用equals()方法更具有保险性。
3.特殊的类类型
enum:枚举类关键字,enum定义了特殊的类继承自java.lang.Enum;其实也是Java中的一种语法糖。
public enum Action{
A,B,C,D}
//反编译
//注意:直接继承自Enum类的程序会被编译器拒绝这里模拟反编译
import java.lang.Enum;
public final class Action extends Enum{
private Action(String s, int i){
super(s,i);}//类构造器权限private,只有内部能实例化
public static final Action A;
public static final Action B;
public static final Action C;
public static final Action D;
//将存入的值定义为静态常量方便实例化后调用
...
static{//在静态代码块中实例化为带序号的对应名称对象
A = new Action("A",0);
B = new Action("B",0);
C = new Action("C",0);
D = new Action("D",0);
...
}
}
在使用时,可直接当作静态常量调用,当方法定义为接收此类类型的参数时,传入时只能输入声明时定义几个的常量。
三.对象初步
1.数组对象
数组:用来接收数据,具有索引的数据结构。
int[] array1 = {1,15,45} ;//声明有三个元素空间的数组并赋初始值
int[] array2 = new int[2];//声明2个连续空间的int数组
array2[0] = 45;
array2[1] = 782;
int[] array3 = new int[]{46,4564,4546,87}
for(int i = 0;i<array1.length;i++){//利用for循环获取数组中的值
if (myList[i] > max) //获取最大值
max = array1[i];
}
System.out.println(max);
for(int s:array2){//增强型for循环是一种语法糖
int total += s; //计算元素之和
System.out.println(total);
}
int[][] array3 = int[2][3];//多维数组的声明
int[][] array4 = {{147,848,456},{546,787,834,628,952}};
//多维数组可看作矩阵,显然它并不完全是,实际上你也可以建立不规则数组
int[][] array5 = new int[2][];
array5[0] = new int[]{54,66,48};
array5[1] = new int[]{45,465,62,89};
- 既然数组也是对象,int[]即是类名称,new方法即创建了int类型的数组实例,即int[]类的对象
- 多维数组也可理解为int[]类型的一维数组实例,即int[][]的对象.这样就理解了数组的多维实际上是一维数组的嵌套层叠
- 使用new新建一个数组时,其每个索引元素都会有默认值(参见本文第一部分)。若默认值需更改,可使用java.util.Arrays的fill()方法来设定新建数组的默认值。
- 特别注意:当声明一个类数组时,
eg:Integer[] arr = new Integer[3];
只声明容量而未赋值的时候,实际上并没有创建出任何对象。多维情况时同样适用。
2.数组复制
在Java中,数组自建立时长度即固定,若长度不够使用,需另建新的数组将原数组复制至新数组中。
浅层复制(Shallow Copy)
使用System.arrayCopy()方法可对数组进行选择复制,它接收五个参数:来源数组,来源起始索引,目的数组,目的起始索引,长度。
JDK1.6以上还可用Arrays.copyOf()方法更加方便的复制数组,并自行建立新数组存储起来int[] s1 = {45,82,84,215,45,98,27,54}; int[] s2 = new int[s1.length]; System.arrayCopy(s1,0,s2,0,s1.length); int[] s3 = Arrays.copyOf(s1,s1.length*2);//第二个参数即为新数组长度
然而实际上,以上两种方法用在类类型声明的数组时,都是执行浅层复制,即只复制数组的指针参考,并没有实际复制出对象。当改变其中一个数组的元素,会使因其复制得到的数组的元素都改变。
- 深层复制(Deep Copy)
当我们复制对象数组时,因为每个对象实例都有各自的属性,用户需要手动将所要复制的对象属性指定到新建的数组中。
class Clothes{//定义一个对象,实例化元素添加到数组
String color;
char size;
Clothes(String color,char size){
this.color = color;
this.size = size;
}
}
public class DeepCopy{
public static void main(String[] args){
Clothes[] c1 = {new Clothes("red",'L'),new Clothes("blue",'M')};
Clothes[] c2 = new Clothes[c1.length];
for(int i = 0;i<c1.length; i++){
Clothers c = new Clothes(c1[i].color, ci[i].size);
c2[i] = c;
}
c1[0].color = "yellow";
System.out.println(c2[0].color);
}
}
3.字符串对象
字符串本质上是打包字符数组的对象,是java.lang.String类的实例。
由于字符串在Java中是对象,所以也就拥有一些可操作的方法,像是可以使用length()方法取得字符串长度,使用charAt()取得字符串指定从0开始索引的某个字符,使用toUppercase()将原本为小写的字符串转换成大写。
如果要将字符串转换成整数、浮点数等基本类型,可以使用一下剖析方法:
方法 | 说明 |
---|---|
Byte.parseByte(num) | 将字符串num剖析成byte类型整数 |
Short.parseShort(num) | 将字符串num剖析成short类型整数 |
Integer.parseInt(num) | 将字符串num剖析成int类型整数 |
Long.parseLong(num) | 将字符串num剖析成long类型整数 |
Float.parseFloat(num) | 将字符串num剖析成float类型浮点数 |
Double.parseDouble(num) | 将字符串num剖析成double类型浮点数 |
4.字符串特性
- 字符串池与字符串常量:
String name1 = "麦克喵";//字符串常量
String name2 = "麦克喵";
String name1 = new String("麦克喵");//字符串池
String name1 = new String("麦克喵");
name1 = name2; //true
name1 = name3; //falst
name3 = name4; //falst
在Java中,为了效率考虑,以“”包括的字符串只要内容相同,无论在程序代码中出现多少次,JVM都只会建立一个Integer实例,并在字符串池中维护,直到GC清除。
即引用一个类型时,看是否创建出一个新的实例,这也是一直在强调的,只是比较实质内容的情况,尽量使用equals()方法。
不可变动字符串
在Java中,字符串对象一旦建立,就无法更改对象中的内容,而使用+连接字符串的情况,实质上是建立了一个java.lang.StringBuilder对象,它使用append()对+左右的字符串进行连接,并通过toString()方法返回String类型。
java.lang.StringBuilder是JDK1.5之后新增的类,在该版本之前,是使用java.lang.StringBuffer类,StringBuilder与StringBuffer具有相同的操作接口,在单机非多线程(Multithread)的情况下,使用StringBuilder会有较好的效率,因为StringBuilder不会处理同步(Synchronized)的问题。
参考文章:
1.关于float类型的剖析
2. 关于 Java 数组的 12 个最佳方法
3.String、StringBuffer与StringBuilder之间区别