1.基本数据类型
Java是一种强类型语言,每个变量都必须声明其数据类型。 Java的数据类型可分为两大类:基本数据类型(primitive data type)和引用数据类型(reference data type)。
Java中定义了3类8种基本数据类型
(1)整形(byte、short、int、long)
整型用于表示没有小数部分的数值,它允许是负数。
Java 语言整型常量的四种表示形式
-
十进制整数,如:99, -500, 0
-
八进制整数,要求以 0 开头,如:015
-
十六进制数,要求 0x 或 0X 开头,如:0x15
-
二进制数,要求0b或0B开头,如:0b01110011
注意:Java语言的整型常数默认为int型,声明long型常量可以后加‘l’或‘ L ’,一般加‘L’。
(2)浮点型(float、double)。
float类型又被称作单精度类型,尾数可以精确到7位有效数字,double表示这种类型的数值精度约是float类型的两倍,又被称作双精度类型,绝大部分应用程序都采用double类型。浮点型常量默认类型也是double。
Java浮点类型常量有两种表示形式
-
十进制数形式,例如:3.14 314.0 0.314
-
科学记数法形式,如314e2 314E2 314E-2
注意:Java语言的浮点型常数默认为double型,声明float类型的数值有一个后缀F 。
由于精度问题,实际使用时应该尽量避免两个浮点数进行比较,同时如果需要进行没有误差的精确数字进行计算,可以使用java.math包中的BigInteger和BigDecimal类。以BigInteger为例,BigDecimal同理:
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal bd = BigDecimal.valueOf(1.0);
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
System.out.println(bd);//0.5
System.out.println(1.0 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1);//0.5000000000000001
}
}
(3)字符型(char)
字符型在内存中占2个字节,在Java中使用单引号来表示字符常量。
char 类型用来表示在Unicode编码表中的字符。Unicode具有从0到65535之间的编码,他们通常用从’\u0000’到’\uFFFF’之间的十六进制值来表示(前缀为u表示Unicode)。
Java 语言中还允许使用转义字符 ‘\’ 来将其后的字符转变为其它的含义。常见转义字符:
(4)布尔型(boolean)
boolean类型有两个常量值,true和false,在内存中占一位(注意:不是一个字节)。
一般不写成if(flag == true)而是写成if(flag)
2.运算符
注意:右移一位除以2(整除),左移一位乘以2。
&和&&的区别:
-
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
-
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长
-
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01
运算符优先级问题:
1.没必要知道,需要的时候,使用()表示运算先后顺序,使程序可读性强。
2.逻辑与、逻辑或、逻辑非的优先级一定要熟悉!(逻辑非>逻辑与>逻辑或)。
如:a||b&&c的运算结果是:a||(b&&c),而不是(a||b)&&c
(重点)类型转化问题:
1.自动类型转换:
自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下:
低--------------------------------------------->高
byte,short,char-> int -> long -> float -> double
运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下:
操作数1类型 |
操作数2类型 |
转换后的类型 |
byte、short、char |
int |
int |
byte、short、char、int |
long |
long |
byte、short、char、int、long |
float |
float |
byte、short、char、int、long、float |
double |
double |
2.强制类型转换:
强制转换的格式是在需要转型的数据前加上“( )”,然后在括号内加入需要转化的数据类型。有的数据经过转型运算后,精度会丢失。
double x = 3.14;
int nx = (int)x; //值为3
char c = 'a';
int d = c+1;
注意:
1.当将一种类型强制转换成另一种类型,而又超出了目标类型的表数范围,就会被截断成为一个完全不同的值。
int x = 300;
byte bx = (byte)x; //值为44
2.不能在布尔类型和任何数值类型之间做强制类型转换。
3.控制语句
选择结构(if 和switch)
import java.util.Scanner;
public class TestIf {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("please input your score");
int x = sc.nextInt();
if(x<60) {
System.out.println("D");
}else if(x<75) {
System.out.println("C");
}else if(x<85) {
System.out.println("B");
}else {
System.out.println("A");
}
}
}
switch基本不用,懒得写了
switch (表达式) {
case 值1:
语句序列1;
[break];
case 值2:
语句序列2;
[break];
… … … … …
[default:
默认语句;]
}
循环结构(while do-while for)注意break和continue
for循环
//计算0~100的和
public class Demo {
public static void main(String[] args) {
int sum = 0;
for(int i=0;i<=100;i++) {
sum += i;
}
System.out.println(sum);
}
}
while循环
//计算0~100的和
public class Demo {
public static void main(String[] args) {
int i = 0;
int sum = 0;
while(i <= 100) {
sum += i;
i++;
}
System.out.println(sum);
}
}
do-while
//计算0~100的和
public class Demo {
public static void main(String[] args) {
int i = 0;
int sum = 0;
do {
sum += i;
i++;
}while(i <= 100);
System.out.println(sum);
}
}
4.方法(函数)
方法的重载(overload):
重载的方法,实际是完全不同的方法,只是名称相同而已!
构成方法重载的条件:
- 不同的含义:形参类型、形参个数、形参顺序(首先要类型不同)不同
- 只有返回值不同不构成方法的重载
- 只有形参的名称不同,不构成方法的重载
public class Demo {
public static void main(String[] args) {
System.out.println(add(3, 5));// 8
System.out.println(add(3, 5, 10));// 18
System.out.println(add(3.0, 5));// 8.0
System.out.println(add(3, 5.0));// 8.0
// 我们已经见过的方法的重载
System.out.println();// 0个参数
System.out.println(1);// 参数是1个int
System.out.println(3.0);// 参数是1个double
}
/** 求和的方法 */
public static int add(int n1, int n2) {
int sum = n1 + n2;
return sum;
}
// 方法名相同,参数个数不同,构成重载
public static int add(int n1, int n2, int n3) {
int sum = n1 + n2 + n3;
return sum;
}
// 方法名相同,参数类型不同,构成重载
public static double add(double n1, int n2) {
double sum = n1 + n2;
return sum;
}
// 方法名相同,参数顺序不同,构成重载
public static double add(int n1, double n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有返回值不同,不构成方法的重载
public static double add(int n1, int n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有参数名称不同,不构成方法的重载
public static int add(int n2, int n1) {
double sum = n1 + n2;
return sum;
}
}
递归:
递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
递归结构包括两个部分:
1.定义递归头:什么时候不调用自身方法,也就是递归的结束条件。如果没有头,将陷入死循环。
2.递归体:什么时候需要调用自身方法。
//计算n的阶乘
public class Demo {
public static void main(String[] args) {
System.out.println(factorial(10));
}
public static long factorial(int n) {
if(n == 1) {//递归头
return 1;
}else {
return n*factorial(n-1); //递归体
}
}
}
利用递归可以用简单的程序来解决一些复杂的问题。比如:斐波那契数列的计算、汉诺塔、快排等问题。但是递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环慢的多,所以在使用递归时要慎重。