一.数据类型转换
(一)为什么要进行数据类型转换?
Java程序中要求参与的计算的数据,必须要保证数据类型的一致性,如果数据类型不一致将发生类型的转换。
(二)自动类型转换(隐式)
1.特点:
将的类型 自动提升为的类型。
- 当一个
byte
类型变量和一个int
变量运算时,byte
类型将会自动提升为int
类型进行运算。
代码
public class Change{
public static void main(String[] args){
int a = 1;
byte b = 2;
// byte x = a + b; // 报错
//int类型和byte类型运算,结果是int类型
int x = a + b;
System.out.println(x);
}
}
运行结果:
- 同样道理,当一个
int
类型变量和一个double
变量运算时,int
类型将会自动提升为double
类型进行运算。
代码:
public class change{
public static void main(String[] args){
int a = 1;
double b = 2.5;
//int类型和double类型运算,结果是double类型
double c = a+b;//int类型会提升为double类型
System.out.println(c);
}
}
运行结果:
2.转换原理图解:
byte
类型内存占有1个字节,在和int
类型运算时会提升为int
类型 ,自动补充3个字节,因此计算后的结果还是int
类型。
3.转换规则:
范围小的类型向范围大的类型提升,byte
、short
、char
运算时直接提升为int
。
byte
、short
、char
‐‐>int
‐‐>long
‐‐>float
‐‐>double
代码:
public class change{
public static void main(String[] args){
byte b1 = 1;
byte b2 = 2;
// byte b3 = b1 + b2;//错误写法,byte类型运算时直接提升为int
int i1 = b1 + b2;//正确写法
System.out.println(i1);//3
short s1 = 1;
short s2 = 2;
// short s3 = s1 + s2;//错误写法,short类型运算时直接提升int
int i2 = s1 + s2;//正确写法
System.out.println(i2);//3
char c1 = 'A';
char c2 = 1;
// char c3 = c1 + c2;//错误写法,char类型运算时直接提升int
int i3 = c1 + c2;//正确写法
System.out.println(i3);//66
}
}
运行结果:
(三)强制类型转换(显式)
1.特点:
将的类型 强制转换成的类型 。
- 比较而言,自动转换是Java自动执行的,而强制转换需要我们自己手动执行。
代码:
public class Change{
public static void main(String[] args){
/*
double类型内存8个字节,int类型内存4个字节。
1.5 是 double 类型,取值范围大于int。
可以理解为double是8升的水壶,int是4升的水壶。
不能把大水壶中的水直接放进小水壶去。
想要赋值成功,只有通过强制类型转换,
将double类型强制转换成int类型才能赋值。
*/
// double类型数据强制转成int类型,直接去掉小数点。
// int i = 1.5;//编译失败
int i = (int)1.5;
System.out.println(i);//1
short s = 1;//short类型变量,内存中2个字节
/*
s和1做运算的时候,1是int类型,s会被提升为int类型
s+1后的结果是int类型,将结果在赋值会short类型时发生错误
short内存2个字节,int类型4个字节
必须将int强制转成short才能完成赋值
*/
// s = s + 1;//编译失败
s = (short)(s+1);
System.out.println(s);//2
}
}
运行结果:
2.转换格式:
- 数据类型 变量名 = (数据类型)被转数据值;
- 例:
int i = (int)1.5;
3.转换原理图解:
(四)注意事项
- 强制类型转换一般不推荐使用,因为有可能发生精度损失、数据溢出。
(例:浮点转成整数,直接取消小数点,可能造成数据损失精度。
int 强制转成 short 砍掉2个字节,可能造成数据丢失。)- byte/short/char这三种类型都可以发生数学运算,例如加法“+”.
- byte/short/char这三种类型在运算的时候,都会被首先提升成为int类型,然后再计算。
- boolean类型不能发生数据类型转换
(五)编码表(数字和字符的对照关系表)
1.概述:
编码表 :就是将人类的文字和一个十进制数进行对应起来组成一张表格。
2.Java中的编码表:
- ASCII码表:American Standard Code for Information Interchange,美国信息交换标准代码。
- Unicode码表:万国码。也是数字和符号的对照关系,开头0-127部分和ASCII完全一样,但是从128开始包含有更多字符。
3.常用编码:
48 - '0'
65 - 'A'
97 - 'a'
Tips:
char c = 'a';
int i = c + 1;
System.out.println(i)//98
在char类型和int类型计算的过程中,char类型的字符先查询编码表,得到97,再和1求和,结果为98。char类型提升为了int类型。char类型内存2个字节,int类型内存4个字节。
(六)编译器的两点优化(自动进行的强制类型转换)
1.第一点
对于byte/short/char三种类型来说,如果右侧赋值的数值没有超过范围,那么javac编译器将会自动隐含地为我们补上一个(byte) (short) (char).
- 如果右侧的数值没有超过左侧的范围,编译器补上强转。
- 如果右侧的数值超过了左侧范围,那么编译器直接报错。
代码:
public class Change{
public static void main(String[] args){
//右侧确实是一个int数字,但是没有超过左侧的范围,就是正确的。
//int --> byte,不是自动类型转换
byte num = 30; //右侧没有超过左侧的范围,相当于:byte num = (byte)30;
System.out.println(num);//30
//int --> char,不是自动类型转换
char ch = 65; //右侧没有超过左侧的范围,相当于:char ch = (char)65;
System.out.println(ch);//A
}
}
运行结果:
2.第二点
- 在给变量进行赋值的时候,如果右侧的表达式当中全都是常量,没有任何变量,那么编译器javac将会直接将若干个常量表达式计算得到结果。
-
short result = 5 + 8;
1等号右边全都是常量,没有任何变量参与运算,编译之后,得到的.class字节码文件当中相当于 :short result = 13;
右侧的常量结果数值,没有超过左侧范围,所以正确。这称为“编译器的常量优化”。 - 但是注意:一旦表达式当中有变量参与,那么就不能进行这种优化了。
代码:
public class Change{
public static void main(String[] args){
byte a = 1;//正确写法,右侧没有超过左侧的范围
byte b = 2;
// byte + byte --> int + int --> int
// byte c1 = b1 + b2;//错误写法,左侧需要是int类型
// System.out.println(c1);
//右侧不用变量,而是采用常量,而且只有两个常量,编译器进行常量优化
byte c2 = 1 + 2;
System.out.println(c2);//3
// byte c3 = 1 + a + 2;//错误写法,只有常量时才会进行优化
}
}
运行结果:
二.运算符
(一)算术运算符
1.分类:
+ 加法运算,字符串连接运算
- 减法运算
* 乘法运算
/ 除法运算
% 取模运算,两个数字相除取余数
++ -- 自增自减运算
- Java中,整数使用以上运算符,无论怎么计算,也不会得到小数。
代码:
public class Operator{
public static void main(String[] args){
int i = 1234;
System.out.println(i/1000*1000);//计算结果是1000
}
}
运行结果:
2.+的多种用途:
(1) 对于数值来说,那就是加法。
(2) 对于字符char
类型来说,在计算之前,char
会被提升成为int
,然后再计算。(char
类型字符和int
类型数字之间的对照关系表:ASCII、Unicode)
(3) 对子字符串String
(首字母大写,并不是关键字)来说,加号代表字符串连接操作。(任何数据类型和字符串进行连接的时候,结果都会变成字符串)
代码:
public class Operator{
public static void main(String[] args){
String str1 = "Hello";
System.out.println(str1);//Hello
//字符串连接
System.out.println(str1 + "World");//HelloWorld
String str2 = "Java";
//String + int --> String
System.out.println(str2 + 20);//Java20
//优先级问题
//String + int + int
//String + int
//String
System.out.println(str2 + 20 + 30);//Java2030
System.out.println(str2 + (20 + 30));//Java50
}
}
运行结果:
3.自增自减运算符++ --:
(1)基本含义:
让一个变量涨一个数字1,或者让一个变量降一个数字1
(2)使用格式:
写在变量名称之前,或者写在变量名称之后。例如;++num,也可以num++
(3)使用方式:
- 单独使用:不和其他任何操作混合,自己独立成为一个步骤。
- 混合使用:和其他操作混合,例如与赋值混合,或者与打印操作混合等。
(4)使用区别:
- 在单独使用的时候,前++和后++没有任何区别。也就是:++num;和num++;是完全一样的。
- 在混合的时候,有【重大区别】
A.如果是前++,那么变量【立刻马上+1】,然后拿着结果进行使用。
B.如果是后++,那么首先使用变量本来的数值,【然后再让变量+1】。
代码:
public class Operator{
public static void main(String[] args){
int a = 1;
int b = ++a;//a=2,b=2
int c = a++;//a=3,c=2
int d = a++ + ++a;//a=5,d=3+5=8
System.out.println(a);//5
System.out.println(b);//2
System.out.println(c);//2
System.out.println(d);//8
}
}
运行结果:
(5)注意事项:
- 只有变量才能使用++ --,常量不可以。
- 自增自减运算符隐含了一个强制类型转换
代码:
public class Operator{
public static void main(String[] args){
//30++;//错误写法,常量不可以使用++或者--
byte a = 1;
// byte b = a + 1;//错误用法,会报错
byte b = ++a;//相当于byte b = (byte)++a;
byte c = --a;//相当于byte c = (byte)--a;
System.out.println(b);//2
System.out.println(c);//1
}
}
运行结果:
(二)赋值运算符
1.分类:
= 等于号
+= 加等于
-= 减等于
*= 乘等于
/= 除等于
%= 取模等
(1)基本赋值运算符:
就是一个等号=
,代表将右侧的数据交给左侧的变量。例:int a = 30;
代码:
(2)复合赋值运算符:
+= a+=3 相当于 a = a+3
-= a-=3 相当于 a = a-3
*= a*=3 相当于 a = a*3
/= a/=3 相当于 a = a/3
%= a%=3 相当于 a = a%3
代码:
public class Operator{
public static void main(String[] args){
int i = 5;
i+=5;//计算方式 i=i+5 变量i先加5,再赋值变量i
System.out.println(i); //10
}
}
运行结果:
2.注意事项:
- 复合赋值运算符其中隐含了一个强制类型转换。
代码:
public class Operator{
public static void main(String[] args){
byte num = 30;
num += 5;//相当于num = (byte)(num+5);
System.out.println(num);
}
}
运行结果:
(三)比较运算符
1.分类:
== 比较符号两边数据是否相等,相等结果是true。
< 比较符号左边的数据是否小于右边的数据,如果小于结果是true。
> 比较符号左边的数据是否大于右边的数据,如果大于结果是true。
<= 比较符号左边的数据是否小于或者等于右边的数据,如果小于结果是true。
>= 比较符号左边的数据是否大于或者等于右边的数据,如果小于结果是true。
!= 不等于符号 ,如果符号两边的数据不相等,结果是true
2.注意事项:
- 比较运算符的结果一定是一个boolean值,成立就是true,不成立就是false
- 如果进行多次判断,不能连着写。
数学当中的写法,例如:1< x <3,程序当中【不允许】这种写法。
代码:
public class Operator{
public static void main(String[] args){
System.out.println(1==1);//true
System.out.println(1<2);//true
System.out.println(3>4);//false
System.out.println(3<=4);//true
System.out.println(3>=4);//false
System.out.println(3!=4);//true
// System.out.println(1 < x < 3);//错误写法!编译报错!不能连着写。
}
}
运行结果:
(四)逻辑运算符
1.分类:
&& 短路与 1.两边都是true,结果是true
2. 一边是false,结果是false
短路特点:符号左边是false,右边不再运算
|| 短路或 1. 两边都是false,结果是false
2. 一边是true,结果是true
短路特点: 符号左边是true,右边不再运算
! 取反 1. ! true 结果是false
2. ! false结果是true
2.注意事项:
(1)逻辑运算符只能用于boolean
值。
(2)与、或需要左右各自有一个boolean
值,但是取反只要有唯一的一个boolean
值即可。
(3)与、或两种运算符,如果有多个条件,可以连续写。
两个条件:条件A&&条件B
多个条件:条件A&&条件B&&条件C
Tips:对于1<x<3的情况,应该拆成两个部分,然后使用与运算符连接起来:
1<x && x<3
代码`:
public class Operator{
public static void main(String[] args) {
boolean a = true;
int x = 2;
System.out.println(true && true);//true
System.out.println(true && false);//false
System.out.println(false && !a);//false,右边不计算
System.out.println(false || false);//false
System.out.println(false || true);//true
System.out.println(true || !a);//true,右边不计算
System.out.println(!false);//true
System.out.println("a="+a);
// System.out.println(1 < x < 3);//错误写法!编译报错!不能连着写。
System.out.println("1< x <3的结果为:" + (1 < x && x < 3));//应该改成这样
}
}
运行结果:
(五)位运算符
1.分类:
& 按位与 a&b a和b每一位进行"与"操作的结果"
| 按位或 a|b a和b每一位进行"或"操作的结果"
~ 取反 ~a a每一位进行"非"操作的结果"
^ 按位异或 a^b a和b每一位进行"异或"操作的结果"
<< 左移 a<<b 将a左移b位,右边空位用0填充
<< 右移 a>>b 将a右移b位,丢弃被移出位,左边做高位用0或1填充
>>> 无符号右移 a>>>b 将a右移b位,丢弃被移出位,左边做高位用0填充
2.说明:
位运算符本质都是针对二进制数0和1进行运算的,在使用位运算符时,都会先将操作数转换成二进制数的形式进行位运算,然后将得到的结果再转换成想要的进制数。其中,1表示true,0表示false。
代码:
public class Operator{
public static void main(String[] args){
int a = 10; // 0000 0000 0000 0000 0000 0000 0000 1010
int b = 20; // 0000 0000 0000 0000 0000 0000 0001 0100
int c = -10; // 1111 1111 1111 1111 1111 1111 1111 0110
System.out.println("a=" + a + ",b=" + b + ",c=" + c);
// a & b 0000 0000 0000 0000 0000 0000 0000 1010(10)
// 0000 0000 0000 0000 0000 0000 0001 0100(20)
// ------------------------------------------ &
// 0000 0000 0000 0000 0000 0000 0000 0000(0)
System.out.println("a&b=" + (a & b));
// a | b 0000 0000 0000 0000 0000 0000 0000 1010(10)
// 0000 0000 0000 0000 0000 0000 0001 0100(20)
// ------------------------------------------ |
// 0000 0000 0000 0000 0000 0000 0001 1110(30)
System.out.println("a|b=" + (a | b));
// ~a 0000 0000 0000 0000 0000 0000 0000 1010(10)
// ------------------------------------------ ~
// 1111 1111 1111 1111 1111 1111 1111 0101(-11)
System.out.println("~a=" + (~a));
// a ^ b 0000 0000 0000 0000 0000 0000 0000 1010(10)
// 0000 0000 0000 0000 0000 0000 0001 0100(20)
// ------------------------------------------ ^
// 0000 0000 0000 0000 0000 0000 0001 1110(30)
System.out.println("a^b=" + (a ^ b));
// a << 1 0000 0000 0000 0000 0000 0000 0000 1010(10)
// ------------------------------------------ <<1
// 0000 0000 0000 0000 0000 0000 0001 0100(20)
System.out.println("a<<1=" + (a << 1));
// a >> 1 0000 0000 0000 0000 0000 0000 0000 1010(10)
// ------------------------------------------ >>1
// 0000 0000 0000 0000 0000 0000 0000 0101(5)
System.out.println("a>>1=" + (a >> 1));
// c >> 1 1111 1111 1111 1111 1111 1111 1111 0110(-10)
// ------------------------------------------ >>1
// 1111 1111 1111 1111 1111 1111 1111 1011(-5)
System.out.println("c>>1=" + (c >> 1));
// a >>> 1 0000 0000 0000 0000 0000 0000 0000 1010(10)
// ------------------------------------------ >>>1
// 0000 0000 0000 0000 0000 0000 0000 0101(5)
System.out.println("a>>>1=" + (a >>> 1));
// c >>> 1 1111 1111 1111 1111 1111 1111 1111 0110(-10)
// ------------------------------------------- >>>1
// 0111 1111 1111 1111 1111 1111 1111 1011(2147483643)
System.out.println("c>>>1=" + (c >>> 1));
}
}
运行结果:
(六)条件运算符(三元运算符)
1.格式:
数据类型 变量名 = 布尔类型表达式?结果1:结果2
2.流程:
(1)首先判断条件是否成立:
(2)如果成立为true,那么将表达式A的值赋值给左侧的变量;
(3)如果不成立为false,那么将表达式B的值赋值给左侧的变量;
3.注意事项:
- 必须同时保证表达式A和表达式B都符合左侧数据类型的要求。
- 三元运算符的结果必须被使用。
代码:
public class Operator{
public static void main(String[] args){
int a = 10;
int b = 20;
double c = 2.5;
//数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;
//判断a > b是否成立,如果成立将a的值赋值给max;如果不成立将b的值赋值给max
int max = a > b ? a : b;
System.out.println("最大值:" + max);
// int result = a > c ? a : c;//错误写法,必须同时保证表达式A和表达式B都符合左侧数据类型的要求
// a > b ? a : b;//错误写法,三元运算符的结果必须被使用
}
}
运行结果:
(七)运算符的优先级
口诀:括号级别最高,逗号级别最低,单目 > 算术 > 位移 > 关系 > 逻辑 > 三目 > 赋值。
三.方法
(一) 概述
我们在学习运算符的时候,都为每个运算符单独的创建一个新的类和main方法,我们会发现这样编写代码非常的繁琐,而且重复的代码过多。能否避免这些重复的代码呢,就需要使用方法来实现。
1.什么是方法?
- 方法:就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能。当我们需要这个功能的时候,就可以去调用。这样即实现了代码的复用性,也解决了代码冗余的现象。
(二) 方法的定义
修饰符 返回值类型 方法名 (参数列表){
方法体
return;
}
Tips:
方法名称的命名规则和变量一样,使用小驼峰。
方法体:也就是大括号当中可以包含任意条语句。
代码:
public static void methodName() {
System.out.println("这是一个方法");
}
(三) 方法的调用
1.为什么要调用
方法在定义完毕后,方法不会自己运行,必须被调用才能执行,我们可以在主方法main中来调用我们自己定义好的方法。在主方法中,直接写要调用的方法名字就可以调用了。
2.调用方法的流程图解
代码:
public class Method{
public static void main(String[] args) {
//调用定义的方法method
method();
}
//定义方法,被main方法调用
public static void method() {
System.out.println("这是自己定义的方法,需要被main调用运行-_-");
}
}
运行结果:
3.调用方法的三种形式
- 直接调用:直接写方法名调用
- 赋值调用:调用方法,在方法前面定义变量,接收方法返回值
- 输出语句调用:在输出语句中调用方法System.out.println(方法名()) 。
代码:
public class Method {
public static void main(String[] args) {
// 单独调用
System.out.print("单独调用:");
sum(10, 20);
System.out.println("===========");
// 打印调用
System.out.print("打印调用:");
System.out.println("变量的值:" + sum(10, 20));
System.out.println("===========");
// 赋值调用
System.out.print("赋值调用:");
int number = sum(15, 25);
System.out.println("变量的值:" + number);
}
public static int sum(int a, int b) {
System.out.println("方法执行啦!");
int result = a + b;
return result;
}
}
运行结果:
(四) 方法重载
1.什么是方法重载
方法重载(OverLoad):指在同一个类中,多个方法的名称一样,但是参数列表不一样(只要它们的参数列表不同即可,与修饰符和返回值类型无关)。
- 参数列表:个数不同,数据类型不同,顺序不同。
- 重载方法调用:JVM通过方法的参数列表,调用不同的方法。
代码:
public class MethodOverLoad {
public static void main(String[] args) {
System.out.println(sum(1, 2));
System.out.println(sum(1, 2, 3));
System.out.println(sum(1, 2, 3, 4));
System.out.println(sum(1, 2, 3, 4, 5));
}
public static int sum(int a, int b) {
System.out.println("可以传入两个参数的方法:");
return a + b;
}
public static int sum(int a, int b, int c) {
System.out.println("可以传入三个参数的方法:");
return a + b + c;
}
public static int sum(int a, int b, int c, int d) {
System.out.println("可以传入四个参数的方法:");
return a + b + c + d;
}
public static int sum(int... params) {
System.out.println("可以传入任意个参数的方法:");
int sum = 0;
for (int i : params) {
sum += i;
}
return sum;
}
}
运行结果:
2.使用方法重载注意事项
(1)方法重载与下列因素相关:
- 参数个数不同
- 参数类型不同
- 参数的多类型顺序不同
(2)方法重载与下列因素无关:
- 与参数的名称无关
- 与方法的返回值类型无关
(五) 方法定义注意事项
- 方法必须定义在类中
- 方法的定义不能产生嵌套包含关系(方法不能定义在另一个方法的里面)
- 不能在 return 后面写代码, return 意味着方法结束,所有后面的代码永远不会执行,属于无效代码。
代码:
public class Method {
public static void main(String[] args){
}
//正确写法,类中,main方法外面可以定义方法
public static void method(){}
}
// public class Method {
// public static void main(String[] args){
// //错误写法,一个方法不能定义在另一方法内部
// public static void method(){}
// }
// }