javaSE(数据类型、运算、逻辑控制、方法)

1.初识Java

JDK、JRE、JVM之间的关系?

JDK(Java Development Kit):Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译器javac与自带的调试工具Jconsole、jstack等。
JRE(Java Runtime Environment):Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程序运行的所需环境。
JVM:Java虚拟机,运行Java代码。
在这里插入图片描述

标识符

在程序中由用户给类名、方法名或者变量所取的名字。
标识符中可以包含:字母、数字以及 下划线和 $ 符号等等。
注意:标识符不能以数字开头,也不能是关键字,且严格区分大小写。

类名:每个单词的首字母大写(大驼峰)
方法名:首字母小写,后面每个单词的首字母大写(小驼峰)
变量名:与方法名规则相同

2.数据类型

四类:整型、浮点型、字符型以及布尔型
八种:
在这里插入图片描述

不论是在16位系统还是32位系统,int都占用4个字节,long都占8个字节
整形和浮点型都是带有符号的
整型默认为int型,浮点型默认为double
字符串属于引用类型,该中类型后序介绍
在java中,如果给定的值超过了数据的范围,那么会直接给你报错

浮点型、字符串、布尔的重点

浮点型变量
单精度浮点型

float num = 1.0f; // 写作 1.0F 也可以
System.out.println(num);

双精度浮点型

注意事项:

  1. double在任何系统下都占8个字节
  2. 浮点数与整数在内存中的存储方式不同,不能单纯使用 的形式来计算
  3. double的包装类型为Double
  4. double 类型的内存布局遵守 IEEE 754 标准(和C语言一样), 尝试使用有限的内存空间表示可能无限的小数, 势必会存在一定的精度误差,因此浮点数是个近似值,并不是精确值。
double num = 1.1;
System.out.println(num * num); // 输出1.21吗?
// 执行结果
1.2100000000000002

字符串类型

计算机中的字符本质上是一个整数. 在 C 语言中使用 ASCII 表示字符, 而 Java 中使用 Unicode 表示字符. 因此一个字符占用两个字节, 表示的字符种类更多, 包括中文.
在Java中使用String类定义字符串类型,比如:

public static void main(String[] args) {
int a=10;
int b=20;
System.out.println("a+b= "+a+b); // a+b表示:将a和b进行拼接
//结果为a+b=1020
System.out.println("a+b= "+(a+b));
System.out.println(a+b+"=a+b");
//结果为a+b=30
//结果为30=a+b
}

在有些情况下,需要将字符串和整形数字之间进行转换:

  1. int 转成 String
int num = 10;
// 方法1
String str1 = num + ""; 
// 方法2
String str2 = String.valueOf(num);
  1. String 转成 int
String str = "100";
String str2 = "1.23";
int num = Integer.parseInt(str);//100
double num2 = Double.parseInt(str2);//1.23

布尔型变量

  1. boolean 类型的变量只有两种取值, true 表示真, false 表示假.
  2. Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.
  3. Java虚拟机规范中,并没有明确规定boolean占几个字节,也没有专门用来处理boolean的字节码指令,在 Oracle公司的虚拟机实现中,boolean占1个字节。
  4. boolean的包装类型为Boolean。
boolean b = true;
System.out.println(b);
b = false;
System.out.println(b);

类型转换

自动类型转换(隐式)

自动类型转换即:代码不需要经过任何处理,在代码编译时,编译器会自动进行处理。特点:数据范围小的转为数据范围大的时会自动进行。

System.Out.println(1024); // 整型默认情况下是int
System.Out.println(3.14); // 浮点型默认情况下是double
1. intlong之间:int会被提升为long
int a = 100;
long b = 10L;
b = a; // a和b都是整形,a的范围小,b的范围大,当将a赋值给b时,编译器会自动将a提升为long类型,然后赋值
a = b; // 编译报错,long的范围比int范围大,会有数据丢失,不安全
float f = 3.14F;
double d = 5.12;
d = f; // 编译器会将f转换为double,然后进行赋值
f = d; // double表示数据范围大,直接将float交给double会有数据丢失,不安全
byte b1 = 100; // 编译通过,100没有超过byte的范围,编译器隐式将100转换为byte
byte b2 = 257; // 编译失败,257超过了byte的数据范围,有数据丢失

强制类型转换(显式)

强制类型转换:当进行操作时,代码需要经过一定的格式处理,不能自动完成。特点:数据范围大的到数据范围小的。

int a = 10;
long b = 100L;
b = a; // int-->long,数据范围由小到大,隐式转换
a = (int)b; // long-->int, 数据范围由大到小,需要强转,否则编译失败
float f = 3.14F;
double d = 5.12;
d = f; // float-->double,数据范围由小到大,隐式转换
f = (float)d; // double-->float, 数据范围由大到小,需要强转,否则编译失败
a = d; // 报错,类型不兼容
a = (int)d; // int没有double表示的数据范围大,需要强转,小数点之后全部丢弃
byte b1 = 100; // 100默认为int,没有超过byte范围,隐式转换
byte b2 = (byte)257; // 257默认为int,超过byte范围,需要显示转换,否则报错
boolean flag = true;
a = flag; // 编译失败:类型不兼容
flag = a; // 编译失败:类型不兼容

总结:

  1. 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型
  2. 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失
  3. 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查
  4. 强制类型转换不一定能成功,不相干的类型不能互相转换

类型提升

不同类型的数据之间相互运算时,数据类型小的会被提升到数据类型大的。

1. int与long之间:int会被提升为long

int a = 10;
long b = 20;
int c = a + b; // 编译出错: a + b==》int + long--> long + long 赋值给int时会丢失数据
long d = a + b; // 编译成功:a + b==>int + long--->long + long 赋值给long

2. byte与byte的运算

对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算.

byte a = 10;
byte b = 20;
byte c = a + b;
System.out.println(c);
// 编译报错
Test.java:5: 错误: 不兼容的类型:int转换到byte可能会有损失

//怎么改???
byte a = 10;
byte b = 20;
byte c = (byte)(a + b);//强制转换
System.out.println(c);

结论: byte 和 byte 都是相同类型, 但是出现编译报错. 原因是, 虽然 a 和 b 都是 byte, 但是计算 a + b 会先将 a和 b 都提升成 int, 再进行计算, 得到的结果也是 int, 这是赋给 c, 就会出现上述错误.
由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short这种低于 4 个字节的类型, 会先提升成 int, 再参与计算

3.运算(易错)

算术运算符

模除运算

System.out.println(10 % -3);//10/-3==-3...1------->1
System.out.println(-10 % 3);//-10/3==-3...-1------->-1
System.out.println(-10 % -3);//-10/-3==3...-1------->-1
System.out.println(11.5 % 2.0);//java中% 不仅可以对整型取模,也可以对double类型取模,但是没有意义,一般都是对整型取模的
// 运行结果 1.5

自增自减

int a = 1;
a++; // 后置++ 表示给a的值加1,此时a的值为2
System.out.println(a++); // 注意:后置++是先使用变量原来值,表示式结束时给变量+1,因此输出2
System.out.println(a); // 输出3
++a; // 前置++ 表示给a的值加1
System.out.println(++a); // 注意:前置++是先给变量+1,然后使用变量中的值,因此输出5
System.out.println(a); // 输出5
// --操作符给操作-1,与++含义类似

注意:
如果单独使用,【前置++】和【后置++】没有任何区别
如果混合使用,【前置++】先+1,然后使用变量+1之后的值,【后置++】先使用变量原来的值,表达式结束时给变量+1
只有变量才能使用自增/自减运算符,常量不能使用,因为常量不允许被修改

逻辑运算符(重点)

逻辑运算符主要有三个: &&、 || 、! ,运算结果都是 boolean类型。

短路求值

System.out.println(10 > 20 && 10 / 0 == 0); // 打印 false System.out.println(10 < 20 || 10 / 0 == 0); // 打印ture
&& 和 || 遵守短路求值的规则. 我们都知道, 计算 10 / 0 会导致程序抛出异常. 但是上面的代码却能正常运行, 说明 10 /0 并没有真正被求值.
对于 && , 如果左侧表达式值为 false, 则表达式结果一定是 false, 无需计算右侧表达式.
对于 ||, 如果左侧表达式值为 true, 则表达式结果一定是 true, 无需计算右侧表达式.

System.out.println(10 > 20 & 10 / 0 == 0); // 程序抛出异常
System.out.println(10 < 20 | 10 / 0 == 0); // 程序抛出异常

& 和 | 如果表达式结果为 boolean 时, 也表示逻辑运算. 但与 && || 相比, 它们不支持短路求值.

位运算符

位运算符主要有四个: & | ~ ^ ,除 ~ 是一元运算符外,其余都是二元运算符。
位操作表示按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的每一位依次进行计算.

条件运算符

条件运算符只有一个:
表达式1 ? 表达式2 : 表达式3
当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值;
当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值。
在这里插入图片描述
输出结果为 false

移位运算(了解)

移位运算符有三个: << >> >>> ,都是二元运算符,且都是按照二进制比特位来运算的。

  1. 左移 <<: 最左侧位不要了, 最右侧补 0.
  2. 右移 >>: 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1).
  3. 无符号右移 >>>: 最右侧位不要了, 最左侧补 0.

总结:

  1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
  2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
  3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
  4. 移动负数位或者移位位数过大都没有意义.

4.逻辑控制

switch语句

执行流程:

  1. 先计算表达式的值
  2. 和case依次比较,一旦有响应的匹配就执行该项下的语句,直到遇到break时结束
  3. 当表达式的值没有与所列项匹配时,执行default

【注意事项】

  • 多个case后的常量值不可以重复
  • switch的括号内只能是以下类型的表达式:
    -基本类型:byte、char、short、int,注意不能是long类型
    -引用类型:String常量串、枚举类型
double num = 1.0;
switch(num) {
	case 1.0:
	System.out.println("hehe");
	break;
	case 2.0:
	System.out.println("haha");
	break;
  }
// 编译出错
Test.java:4: 错误: 不兼容的类型:double转换到int可能会有损失
switch(num) {
}
  • switch 不能表达复杂的条件
// 例如: 如果 num 的值在 10 到 20 之间, 就打印 hehe
// 这样的代码使用 if 很容易表达, 但是使用 switch 就无法表示.
if (num > 10 && num < 20) {
	System.out.println("hehe");
}

break和continue

break 的功能是让循环提前结束.
continue 的功能是跳过这次循环, 立即进入下次循环.

break:找到 100 - 200 中第一个 3 的倍数
int num = 100;
while (num <= 200) {
	if (num % 3 == 0) {
	System.out.println("找到了 3 的倍数, 为:" + num);
	break;
  }
	num++;
}
// 执行结果  找到了 3 的倍数, 为:102


continue :找到 100 - 200 中所有 3 的倍数
int num = 100;
while (num <= 200) {
	if (num % 3 != 0) {
	num++; // 这里的 ++ 不要忘记! 否则会死循环.
	continue;
   }
	System.out.println("找到了 3 的倍数, 为:" + num);
	num++;
}

键盘输入

使用 Scanner 读取字符串/整数/浮点数

import java.util.Scanner; // 需要导入 util 包
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的姓名:");
String name = sc.nextLine();
System.out.println("请输入你的年龄:");
int age = sc.nextInt();
System.out.println("请输入你的工资:");
float salary = sc.nextFloat();
System.out.println("你的信息如下:");
System.out.println("姓名: "+name+"\n"+"年龄:"+age+"\n"+"工资:"+salary);
sc.close(); // 注意, 要记得调用关闭方法

补充
1.String name = scan.next();的缺点在于,输入一组字符串遇到空格就结束了
2.如果scan.nextLine()放在后面,那么需要scan.nextLine();去读取空格
在这里插入图片描述

使用 Scanner 循环读取 N 个数字,并求取其平均值

Scanner sc = new Scanner(System.in);
int sum = 0;
int num = 0;
while (sc.hasNextInt()) {
	int tmp = sc.nextInt();
	sum += tmp;
	num++;
	}
System.out.println("sum = " + sum);
System.out.println("avg = " + sum / num);
sc.close();

注意事项: 当循环输入多个数据的时候, 使用 ctrl + z 来结束输入 (Windows 上使用 ctrl + z, Linux / Mac 上使用 ctrl+ d).

随机数

系统自动生成一个随机整数(1-100), 然后由用户输入一个猜测的数字. 如果输入的数字比该随机数小, 提示 “低了”, 如果输入的数字比该随机数大, 提示 “高了” , 如果输入的数字和随机数相等, 则提示 “猜对了” .

import java.util.Random;
import java.util.Scanner;
class Test {
	public static void main(String[] args) {
	Random random = new Random(); // 默认随机种子是系统时间
	Scanner sc = new Scanner(System.in);
	int toGuess = random.nextInt(100);
	// System.out.println("toGuess: " + toGuess);
	while (true) {
		System.out.println("请输入要输入的数字: (1-100)");
		int num = sc.nextInt();
		if (num < toGuess) {
			System.out.println("低了");
		} else if (num > toGuess) {
			System.out.println("高了");
		} else {
			System.out.println("猜对了");
			break;
		}
	}
	sc.close();
  }
}

5. 方法的使用

调用方法—>传递参数—>找到方法地址—>执行被调方法的方法体—>被调方法结束返回—>回到主调方法继续往下执行

// 方法定义
修饰符 返回值类型 方法名称([参数类型 形参 ...]){
方法体代码;
[return 返回值];
}

实现一个函数,检测一个年份是否为闰年
public class Method{
// 方法定义
public static boolean isLeapYear(int year){
if((0 == year % 4 && 0 != year % 100) || 0 == year % 400){
	return true;
	}else{
	  return false;
	}
  }
}

实参和形参的关系

对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用

public class TestMethod {
public static void main(String[] args) {
	int a = 10;
	int b = 20;
	swap(a, b);
	System.out.println("main: a = " + a + " b = " + b);
}
	public static void swap(int x, int y) {
		int tmp = x;
		x = y;
		y = tmp;
		System.out.println("swap: x = " + x + " y = " + y);
	}
}
// 运行结果
swap: x = 20 y = 10
main: a = 10 b = 20

在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体。
实参a和b是main方法中的两个变量,其空间在main方法的栈(一块特殊的内存空间)中,而形参x和y是swap方法中的两个变量,x和y的空间在swap方法运行时的栈中,因此:实参a和b 与 形参x和y是两个没有任何关联性的变量,在swap方法调用时,**只是将实参a和b中的值拷贝了一份传递给了形参x和y,**因此对形参x和y操作不会对实参a和b产生任何影响。

【解决办法】: 传引用类型参数 (例如数组来解决这个问题)

public class TestMethod {
	public static void main(String[] args) {
		int[] arr = {10, 20};
		swap(arr);
		System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
	}
	public static void swap(int[] arr) {
		int tmp = arr[0];
		arr[0] = arr[1];
		arr[1] = tmp;
	}
}
// 运行结果
arr[0] = 20 arr[1] = 10

方法重载

在自然语言中,一个词语如果有多重含义,那么就说该词语被重载了,具体代表什么含义需要结合具体的场景。在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。

注意:

  1. 方法名必须相同
  2. 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
  3. 与返回值类型是否相同无关
  4. 编译器在编译代码时,会对实参类型进行推演,根据推演的结果来确定调用哪个方法
public class TestMethod {
	public static void main(String[] args) {
		add(1, 2); // 调用add(int, int)
		add(1.5, 2.5); // 调用add(double, double)
		add(1.5, 2.5, 3.5); // 调用add(double, double, double)
	}
	public static int add(int x, int y) {
		return x + y;
		}
	public static double add(double x, double y) {
		return x + y;
	}
	public static double add(double x, double y, double z) {
		return x + y + z;
	}
}

方法签名(为什么能方法重载)

在同一个作用域中不能定义两个相同名称的标识符。比如:方法中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?

  • 方法签名即:经过编译器编译修改过之后方法最终的名字。
  • 具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值