java学习笔记(持续更新)
java学习笔记
一、Java 基础语法(学习于菜鸟教程)
1、第一个java程序
下面看一个简单的 Java 程序,它将打印字符串 Hello World
public class test1 {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
运行结果:
2、 基本语法
编写 Java 程序时,应注意以下几点:
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
3、 Java 标识符
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于 Java 标识符,有以下几点需要注意:
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
4、 Java修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
在后面的章节中我们会深入讨论 Java 修饰符。
5、 Java 变量
Java 中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
6、 Java 数组
数组是储存在堆上的对象,可以保存多个同类型变量。在后面的章节中,我们将会学到如何声明、构造以及初始化一个数组。
7、 Java 枚举
Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。
例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁。
实例:
class FreshJuice {
enum FreshJuiceSize{ SMALL, MEDIUM , LARGE }
FreshJuiceSize size;
}
public class FreshJuiceTest {
public static void main(String[] args){
FreshJuice juice = new FreshJuice();
juice.size = FreshJuice.FreshJuiceSize.MEDIUM ;
}
}
8、 Java 空行
空白行或者有注释的行,Java 编译器都会忽略掉。
二、 Java 对象和类
1、Java作为一种面向对象语言。
支持以下基本概念:
多态 继承 封装
抽象 类 对象
实例 方法 重载
2、java中的类
3、import 语句
在 Java 中,如果给出一个完整的限定名,包括包名、类名,那么 Java 编译器就可以很容易地定位到源代码或者类。import 语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
例如,下面的命令行将会命令编译器载入 java_installation/java/io 路径下的所有类
import java.io.*;
三、Java 基本数据类型
1、 内置数据类型
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
byte:
- byte 数据类型是8位、有符号的,以二进制补码表示的整数;
- 最小值是 -128(-2^7);
- 最大值是 127(2^7-1);
- 默认值是 0;
- byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1);
- Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是 0;
- 例子:short s = 1000,short r = -20000。
int:
- int 数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一般地整型变量默认为 int 类型;
- 默认值是 0 ;
- 例子:int a = 100000, int b = -200000。
long:
- long 数据类型是 64 位、有符号的以二进制补码表示的整数;
- 最小值是 -9,223,372,036,854,775,808(-2^63);
- 最大值是 9,223,372,036,854,775,807(2^63 -1);
- 这种类型主要使用在需要比较大整数的系统上;
- 默认值是 0L;
- 例子: long a = 100000L,Long b = -200000L。
"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。
float:
- float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float 在储存大型浮点数组的时候可节省内存空间;
- 默认值是 0.0f;
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f。
double:
- double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型为double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是 0.0d;
- 例子:double d1 = 123.4。
boolean:
- boolean数据类型表示一位的信息;
- 只有两个取值:true 和 false;
- 这种类型只作为一种标志来记录 true/false 情况;
- 默认值是 false;
- 例子:boolean one = true。
char:
- char类型是一个单一的 16 位 Unicode 字符;
- 最小值是 \u0000(即为0);
- 最大值是 \uffff(即为65,535);
- char 数据类型可以储存任何字符;
- 例子:char letter = 'A';。
2、引用类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
- 例子:Site site = new Site("Runoob")。
3、 Java 常量
常量在程序运行时是不能被修改的。
在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
final double PI = 3.1415927;
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。
字面量可以赋给任何内置类型的变量。例如:
byte a = 68;
char a = 'A'
byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
当使用字面量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制, 例如:
int decimal = 100;
int octal = 0144;
int hexa = 0x64;
和其他语言一样,Java的字符串常量也是包含在两个引号之间的字符序列。下面是字符串型字面量的例子:
"Hello World"
"two\nlines"
"\"This is in quotes\""
字符串常量和字符常量都可以包含任何Unicode字符。例如:
char a = '\u0001';
String a = "\u0001";
四、字符和字符串(此章之后转廖雪峰网站学习)练习题问题解决
可以直接用转义字符\u
+Unicode编码来表示一个字符:
public class test4 {
public static void main(String[] args) {
char c1 = '\u0041'; // 'A',因为十六进制0041 = 十进制65
char c2 = '\u4e2d'; // '中',因为十六进制4e2d = 十进制20013
System.out.println("\\u0041:"+c1);
System.out.println("\\u4e2d:"+c2);
}
}
如,"abc"xyz"
,编译器就无法判断中间的引号究竟是字符串的一部分还是表示字符串结束。这个时候,我们需要借助转义字符\
:
String s = "abc\"xyz"; // 包含7个字符: a, b, c, ", x, y, z
常见的转义字符包括:
\"
表示字符"
\'
表示字符'
\\
表示字符\
\n
表示换行符\r
表示回车符\t
表示Tab\u####
表示一个Unicode编码的字符
从Java 13开始,字符串可以用"""..."""
表示多行字符串(Text Blocks)了。举个例子:public class Main {
public static void main(String[] args) {
String s = """
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC
""";
System.out.println(s);
}
}
因为我安装的是jdk1.8所以会出现下列情况:
1、不可变特性
Java的字符串除了是一个引用类型外,还有个重要特点,就是字符串不可变。
执行String s = "hello";
时,JVM虚拟机先创建字符串"hello"
,然后,把字符串变量s
指向它:
s
│
▼
┌───┬───────────┬───┐
│ │ "hello" │ │
└───┴───────────┴───┘
紧接着,执行s = "world";
时,JVM虚拟机先创建字符串"world"
,然后,把字符串变量s
指向它:
s ──────────────┐
│
▼
┌───┬───────────┬───┬───────────┬───┐
│ │ "hello" │ │ "world" │ │
└───┴───────────┴───┴───────────┴───┘
原来的字符串"hello"
还在,只是我们无法通过变量s
访问它而已。因此,字符串的不可变是指字符串内容不可变。
2、空值null
与c语言不同然后只是和c语言一样定义int a这种,a不是随机值而是
null。
特例:
String s4 = ""; // s4指向空字符串,不是null
练习
请将一组int值视为字符的Unicode编码,然后将它们拼成一个字符串
代码如下:
public class test4 {
public static void main(String[] args) {
char c1 = '\u0041'; // 'A',因为十六进制0041 = 十进制65
char c2 = '\u4e2d'; // '中',因为十六进制4e2d = 十进制20013
System.out.println("\\u0041:"+c1);
System.out.println("\\u4e2d:"+c2);
int a = 72;
int b = 105;
int c = 65281;
// FIXME:
String s = ""+(char)a + (char)b + (char)c;
System.out.println(s);
String s1 = (char)a + (char)b + (char)c +""; // 65458
System.out.println(s1);
}
}
String s = ""+(char)a + (char)b + (char)c;
System.out.println(s);
String s1 = (char)a + (char)b + (char)c +""; // 65458
System.out.println(s1);
结果不同的原因:
1、先做 char类型的加法,然后再+空字符串的,所以最后的结果就是字符串"65458"
2、 是先转换成字符串,再把char类型加到字符串中的
第二种可以改为:
String s = String.format("%c%c%c", a, b, c);
为什么加”“
(char)a +(char)b +(char)c 执行的是 char 与 char 的加运算,结果还是 char 类型,无法赋值给 String 类型的 s。
五、数组类型
1、数组初体验
代码:
int[] ns = new int[5];
ns[0] = 68;
ns[1] = 79;
ns[2] = 91;
ns[3] = 85;
ns[4] = 62;
int i =0;
for (i=0;i<=4;i++) {
System.out.println(ns[i]);
定义一个数组类型的变量,使用数组类型“类型[]”,例如,int[]
。和单个基本类型变量不同,数组变量初始化必须使用new int[5]
表示创建一个可容纳5个int
元素的数组。
Java的数组有几个特点:
- 数组所有元素初始化为默认值,整型都是
0
,浮点型是0.0
,布尔型是false
; - 数组一旦创建后,大小就不可改变。
可以用数组变量.length
获取数组大小:
System.out.println(ns.length); // 5
六、流程控制
1、输出
print为直接输入而printf为输入后换行
2、格式化输出
Java的格式化功能提供了多种占位符,可以把各种数据类型“格式化”成指定的字符串:
占位符 | 说明 |
---|---|
%d | 格式化输出整数 |
%x | 格式化输出十六进制整数 |
%f | 格式化输出浮点数 |
%e | 格式化输出科学计数法表示的浮点数 |
%s | 格式化字符串 |
3、输入
String name = scanner.nextLine(); // 读取一行输入并获取字符串
int age = scanner.nextInt(); // 读取一行输入并获取整数
4、练习
请帮小明同学设计一个程序,输入上次考试成绩(int)和本次考试成绩(int),然后输出成绩提高的百分比,保留两位小数位(例如,21.75%)。
Scanner scanner1 = new Scanner(System.in);
System.out.print("小明请输入上次的成绩:");
int new_chengji = scanner1.nextInt();
System.out.print("小明请输入这次的成绩:");
int old_chengji = scanner1.nextInt();
double percent = 100*((double)old_chengji -(double)new_chengji)/new_chengji;
System.out.printf("成绩提高了:%.2f%%",percent);
5、 if判断
if (条件) {
// 条件满足时执行
}
要判断引用类型的变量内容是否相等,必须使用equals()
方法:
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.println(s1);
System.out.println(s2);
if (s1.equals(s2)) {
System.out.println("s1 equals s2");
} else {
System.out.println("s1 not equals s2");
}
}
}
注意:执行语句s1.equals(s2)
时,如果变量s1
为null
,会报NullPointerException
要避免NullPointerException
错误,可以利用短路运算符&&
if (s1 != null && s1.equals("hello")) {
还可以把一定不是null
的对象"hello"
放到前面:例如:if ("hello".equals(s)) { ... }
。
6、练习
请用if ... else
编写一个程序,用于计算体质指数BMI,并打印结果。
BMI = 体重(kg)除以身高(m)的平方
BMI结果:
-
过轻:低于18.5
-
正常:18.5-25
-
过重:25-28
-
肥胖:28-32
-
非常肥胖:高于32
Scanner ss=new Scanner(System.in); System.out.println("***计算体质指数BMI***"); System.out.println(); System.out.print("你的身高是多少(m) :"); double height=ss.nextDouble(); System.out.print("体重多少(kg) :"); double weight=ss.nextDouble(); double BMI=weight / (height*height); System.out.println(BMI); if(BMI>32) { System.out.println("过于肥胖"); } else if(BMI>28&&BMI<=32) { System.out.println("肥胖"); } else if(BMI>25&&BMI<=28) { System.out.println("过重"); } else if(BMI>18.5&&BMI<=25) { System.out.println("正常"); } else { System.out.print("过轻"); }
7、switch多重选择
1、 switch表达式
使用switch
时,如果遗漏了break
,就会造成严重的逻辑错误,而且不易在源代码中发现错误。从Java 12开始,switch
语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要break
语句
public class Main {
public static void main(String[] args) {
String fruit = "apple";
switch (fruit) {
case "apple" -> System.out.println("Selected apple");
case "pear" -> System.out.println("Selected pear");
case "mango" -> {
System.out.println("Selected mango");
System.out.println("Good choice!");
}
default -> System.out.println("No fruit selected");
}
}
}
使用新的switch
语法,不但不需要break
,还可以直接返回值。把上面的代码改写如下:
public class Main {
public static void main(String[] args) {
String fruit = "apple";
int opt = switch (fruit) {
case "apple" -> 1;
case "pear", "mango" -> 2;
default -> 0;
}; // 注意赋值语句要以;结束
System.out.println("opt = " + opt);
}
}
8、练习
使用switch
实现一个简单的石头、剪子、布游戏。
System.out.println("please choice:");
System.out.println(" 1: 石头");
System.out.println(" 2: 剪刀");
System.out.println(" 3: 布");
Scanner scanner3 = new Scanner(System.in);// 用户输入:
int choice = scanner3.nextInt();
// 计算机随机数 1, 2, 3:
int random = 1 + (int)(Math.random() * 3);
switch (choice) {
case 1:
switch (random) {
case 1:
System.out.println("你选择出了石头\n" +"电脑也出了石头\n" +"平局");
break;
case 2:
System.out.println("你选择出了石头\n" +"电脑出了剪刀\n" + "您赢了");
break;
case 3:
System.out.println("你选择出了石头\n" +"电脑出了布\n" + "您输了");
break;
}
break;
case 2:
switch (random) {
case 1:
System.out.println("你选择出了剪刀\n" +"电脑出了石头\n" +"您输了");
break;
case 2:
System.out.println("你选择出了剪刀\n" +"电脑也出了剪刀\n" + "平局");
break;
case 3:
System.out.println("你选择出了剪刀\n" +"电脑也出了布\n" + "您赢了");
break;
}
break;
case 3:
switch (random) {
case 1:
System.out.println("你选择出了布\n" +"电脑出了石头\n" +"您赢了");
break;
case 2:
System.out.println("你选择出了布\n" +"电脑出了剪刀\n" + "您输了");
break;
case 3:
System.out.println("你选择出了布\n" +"电脑也出了布\n" + "平局");// TODO:
break;
}
break;
}
}
9、小结
switch
语句可以做多重选择,然后执行匹配的case
语句后续代码;
switch
的计算结果必须是整型、字符串或枚举类型;
注意千万不要漏写break
,建议打开fall-through
警告;
总是写上default
,建议打开missing default
警告;
从Java 14开始,switch
语句正式升级为表达式,不再需要break
,并且允许使用yield
返回值。
10、 while循环
表面上看,上面的while
循环是一个死循环,但是,Java的int
类型有最大值,达到最大值后,再加1会变成负数,结果,意外退出了while
循环。
使用while
计算从m
到n
的和:
11、do while循环
使用do while
循环计算从m
到n
的和。
12、 for循环
除了while
和do while
循环,Java使用最广泛的是for
循环。
for
循环的功能非常强大,它使用计数器实现循环。for
循环会先初始化计数器,然后,在每次循环前检测循环条件,在每次循环后更新计数器。计数器变量通常命名为i
。
我们把1到100求和用for
循环改写一下
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i=1; i<=100; i++) {
sum = sum + i;
}
System.out.println(sum);
}
}
但是,很多时候,我们实际上真正想要访问的是数组每个元素的值。Java还提供了另一种for each
循环,它可以更简单地遍历数组:
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int n : ns) {
System.out.println(n);
}
}
}
给定一个数组,请用for
循环倒序输出每一个元素:
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int i= ns.length-1; i>=0; i--) {
System.out.println(ns[i]);
}
}
}
圆周率π可以使用公式计算:
\frac{\mathrm\pi}4=1-\frac13+\frac15-\frac17+\frac19-\dots4π=1−31+51−71+91−…
请利用for
循环计算π:
double pi = 0;
for (int i = 1; i < 100000; i += 4) {
// TODO:
pi += 4 * (Math.pow(i, -1) - Math.pow(i + 2, -1));
}
System.out.println(pi);
13、 break和continue
无论是while
循环还是for
循环,有两个特别的语句可以使用,就是break
语句和continue
语句。
1、 break
在循环过程中,可以使用break
语句跳出当前循环。
使用for
循环计算从1到100时,我们并没有在for()
中设置循环退出的检测条件。但是,在循环内部,我们用if
判断,如果i==100
,就通过break
退出循环。
因此,break
语句通常都是配合if
语句使用。
2、 continue
break
会跳出当前循环,也就是整个循环都不会执行了。而continue
则是提前结束本次循环,直接继续执行下次循环。
break
语句可以跳出当前循环;
break
语句通常配合if
,在满足条件时提前结束整个循环;
break
语句总是跳出最近的一层循环;
continue
语句可以提前结束本次循环;
continue
语句通常配合if
,在满足条件时提前结束本次循环。