JAVASE语言学习
前言
你好! 这是我的一篇博客,主要讲述java se 相关知识,主要内容来自于学习传智播客网课后我自己的理解和总结。
JAVA 准备知识
###JAVA的发展历史
JAVA语言之父是James Goslin, 1995年推出的高级编程语言。
经过这么多年的发展,已经有多个版本,其中 java 5.0和8.0是改动比较大的版本。
计算机进制的相互转化
主要掌握二、八、十、十六进制的相互转换。
- 十进制转二进制:使用除以2取余数的方法(注意是倒序)。
- 二进制转十进制,用权重法即可,同理可以应用到八进制和十六进制。
- 二进制转八进制,每三位就是八进制的一位。
windows系统的命令行操作
命令 | 操作 |
---|---|
盘符切换 | 盘符: 如 C: |
查看当前文件夹 | dir |
进入文件夹 | cd 文件夹 |
退出文件夹 | cd… |
退出到磁盘根目录 | cd \ |
清屏 | cls |
-
使用cd命令时,可以使用TAB键取补全文件名,从而加快速度。
-
JDK > JRE > JVM
-
安装 JDK 的时候,路径最好不要有空格和中文,JDK 已经包含了JRE, 所以可以取消掉公共JRE安装项。
-
配置环境变量:在cmd任意位置使用calc、Notepad等程序,只要在命令行直接输入即可,这是因为配置了环境变量的缘故,同理,配置JAVA的环境变量作用也是如此,在任意位置使用javac等命令均可,而无需进入JDK安装目录去调用javac程序。
-
JAVA单行注释,以//开头,换行就结束。
-
多行注释,以 /* 开头,*/ 结束。
-
标识符:在程序中我们自己定义的内容。比如类名字、方法名字、变量的名字等等,都属于标识符。
1. 命名规则(硬性要求):
- 标识符可以包含英文字母26个(区分大小写),0-9数字,$美元符号和_下划线
- 标识符不能以数字开头。
- 标识符不能是关键字。
2. 命名规范(软性建议):
- 类名:首字母大写,后面每个单词首字母大写。
- 方法名:首字母小写,后面每个单词首字母大写。
- 变量名:全部小写。
常量,变量以及注意事项
- 常量:在程序运行期间固定不变的量。分类如下:
- 字符串常量:发誓用双引号引起来的部分,就叫做字符串常量。例如:“abc”、“123”。注意:System.out.println(""); // 双引号内为空也是可以的。
- 整数常量:直接写上的数字,没有小数点。可以打印负数,例如:System.out.println (-500).
- 浮点数常量:直接写上数字的,有小数点。例如:2.5,-3.24,0.0。
- 字符常量:凡是用单引号引起来的单个字符,就是字符常量。例如:‘A’, ‘b’, ‘9’, ‘中’. 需要注意的是:两个单引号中间必须有且仅有一个字符,没有不行,两个也不行。
- 不二常量:true,false。
- 空常量: null。
- 变量:在程序中可以变化的量就是变量。
- Java要求一个变量每次只能保存一个数据,必须要明确保存的数据类型。
- Java数据类型:
a. 基本数据类型:包括整数、浮点数、字符、布尔。
b. 引用数据类型:包括类、数组、接口。
基本数据类型 | 英文 | 内存占用 | 取值范围 |
---|---|---|---|
字节型 | byte | 1个字节 | -128~127 |
短整型 | short | 2个字节 | -32768~32767 |
整型 | int(默认) | 4个字节 | -2 31 ^{31} 31~2 31 − 1 ^{31}-1 31−1 |
长整型 | long | 8个字节 | -2 63 ^{63} 63~2 63 − 1 ^{63}-1 63−1 |
单精度浮点型 | float | 4个字节 | 1.4013E-45~3.4028+38 |
双精度浮点型 | double (默认) | 8个字节 | 4.9E-324~1.7977E+308 |
字符型 | char | 2个字节 | 0~65535 |
布尔型 | boolean | 1个字节 | true,false |
- Java默认类型:整数为int,浮点类型为double。
- 如果创建了多个变量,那么变量之间的名称不可以重复(在作用域中,即是从定义变量的一行开始,一直到直接所属的大括号结束为止)。
- 对于float,long类型来说,字母后缀的F和L不可以丢掉。例如:long l = 1234524L; float f = 5.5F;
- 定义的变量,没有赋值不能够使用。
- 变量的使用不能超过作用域的范围。
- int x = 100, y = 200, z = 300; 这样可以同时创建和赋值。(一般情况下不推荐这么写)。
数据类型的转换
自动转换
- long num1 = 100;/* 100的默认数据类型是int型, int --> long符合数据范围从小到大的要求,所以这一行代码发生了自动类型转换 */
- int i = 1;
byte b = 2;
int j = b + i; // 结果是int类型
byte j = b + i; // 错误 - float num3 = 30L
System.out.println(num3); // 30.0 - 转换规则,范围小的类型向范围大的类型提升,byte、short、char --> int --> long --> long --> float --> double
强制转换
- int num = (int) 100L; // 强制转换的格式
- short s = 1;
s = s + 1; /* 错误,s + 1 发生自动类型转换,由小到大,变成了 int类型,之后又赋给s这个short类型,发生错误,必须完成如下的强制格式转换 */
s = (short) (s+1); - 强制类型转换一般不推荐使用,有可能会发生精度损失、数据溢出。
- boolean型不能发生类型转换。
- byte/short/char这三种类型在运算的时候,都会被首先提升成为int类型然后在计算。
- int num3 = (int) 3.99;
System.out.println (num3); // 3 - char zifu1 = ‘a’;
System.out.println (zifu1); // a
System.out.println (zifu1 + 1); // 98
ASCII 编码表
ASCII码表:American Standard Code for Information Interchange: 美国信息交换标准代码。
Unicode: 万国码。也是数字和符号的对照关系,开头0-127部分和ASCII一样,但是从128开始包含有更多字符。
需要记住的几个字符和数值对应:
字符 | 对应数值 |
---|---|
0 | 48 |
9 | 57 |
A | 65 |
Z | 90 |
a | 97 |
z | 122 |
运算符
算数运算符号
注意操作 | 意义 |
---|---|
% | 取模运算,两个数字相除取余数 |
++ , - - | 自增和自减 |
其他 | 加减乘除 |
- Java 运算中,如果是整数的运算,那么无论怎么计算,也不会得到小数。
- 一旦运算中有不同类型的数据那么结果将会是数据类型范围大的那种。
double result = x + 2.5; /* int + double --> double + double --> double */ - 变量前++:变量先把自己的值加一,加一后的结果再去运算。
public static void main (String[] args){
int a = 1;
int b = ++a;
System.out.println(a); //a
System.out.println(b); //b
}
后++就是先赋值再自加。
- +在遇到字符串的时候,表示的是连接,拼接的含义。
public static void main(String[] args){
System.out.println("5+5="+5+5); \\ 5+5=55,String + int --> String
}
- 优先级问题:
System.out.println(str2 + (20 + 30)); // Java50
- 只有变量才可以自增和自减,常量不能发生改变,所以不能使用自增、自减运算符。
- 复合赋值运算符其中隐含了一个强制的类型转换。
byte num = 30;(这个地方,在等号后面是一个int型常量,jvm会自动将其转换为byte类型,注意的是,如果等号后面是3.0这样的double类型则也会报错)
num = num + 1;(这个地方会报错。因为等号后面是一个表达式,jvm不会进行自动转换,会报精度损失的错误)
num += 1;(这里不会报错,因为jvm中复合运算符会自动向低精度转化,相当于有一个强转过程)
值得注意有一点:+=和+的区别除了上述的一点外还有一点:
复合运算符:a +=1;是先计算a的值(如果a中有方法则会执行方法),然后将计算的结果放入一个中间变量当中,然后再进行其他运算,最后赋值给a。而a = a + 1;是计算a+1的值,在这个过程中,如果a中有方法也会执行方法,最后赋值给a的时候会再次运行a中方法,相当于两次运算。
// num = num + 5;
// num = byte + int;
// num = int + int;
// num = int;
// num = (byte) int;
赋值运算符
操作 | 意义 |
---|---|
/= | 除等于 |
比较运算符
操作 | 意义 |
---|---|
>= | 大于等于 |
!= | 不等于,如果符号两方的数不相等,结果为true。 |
- 比较运算符,是两个数据之间进行比较的运算,运算的结果都是布尔值 true 或者 false。
逻辑运算符
操作 | 意义 |
---|---|
&& 短路与 | 符号左边是false,则右边不再运算 |
||短路或 | 符号左边是true,则右边不再运算 |
! | 取反 |
- 逻辑运算符是用来连接两个布尔类型结果的运算符,运算结果都是布尔值 true 和 false。
- 对于 1 < x < 3 的情况,应该拆分为两个部分,然后使用与运算符连接起来:
int x = 2;
1 < x && x < 3; - int a = 10;
System.out.println(3 > 4 && ++a < 100); //false
System.out.println(a); // 10
三元运算符
- int max = a > b ? a : b;
- int result = 3 > 4 ? 2.5 : 10; //错误,必须保证 ?后面的两个表达式都符合左侧数据类型的要求。
- a > b ? a : b; // 错误,三元运算符的结果必须被使用。
方法
- 格式:
修饰符 返回值类型 方法名 (参数列表){
代码…
return;
} - public class Demo11Method {
public static void main(String[] args) {
farmer ();
}
public static void cook () {
System.out.println ();
}
} - 方法必须定义在一类中方法外。
- 方法不能在另一个方法里面进行定义。
使用JShell
- 当我们编写的代码量很少的时候,而有不愿意编写类,main方法,也不愿意去编译和运行,这个时候就可以使用JShell工具。
扩展知识点
- 对于 byte/short/char 三种类型来说,如果右侧复制的数值没有超过范围,那么javac编译器将会自动隐含地为我们补上一个(byte)(short)(char)
byte num1 = /* (byte) */ 30;
System.out.println (num1);
char zifu = /* (char) */ 65;
System.out.println (zifu); // A
- +=是一个运算符,只能运算一次,并且带有强制转换的特点。
public static void main(String[] args){
short s = 1;
s += 1;
System.out.println (s);
}
以上的程序不会报错,理论上 += 是两次运算,实际上只是一次运算,并且带有强制转换的特点,也就是说 s += 1; 实际上是 s = (short) (s + 1), 因此程序没有问题,运行结果是2。
- 编译器的常量优化
public static void main(String[] args){
byte b1 = 1;
byte b2 = 2;
byte b3 = 1 + 2;
byte b4 = b1 + b2;
byte b5 = 1 + 2 + b1;
}
以上程序,b3不会报错,因为javac在编译的时候,右边全是常量所以会直接得到运算结果,相当于是: byte b3 = 3;
而b4、b5会报错,存在变量运算,javac不清楚变量的结果是什么,因此结果会以int类型进行处理,int类型不能赋值给byte类型,因此编译失败。
流程控制语句
if (判断语句){
执行语句;
} else if {
执行语句;
}
- switch 语句
public class Demo07Switch {
switch () {
case 1:
'''
break;
case 2:
'''
break;
default:
'''
break;
}
- 多个case后面的数值不可以重复。
- switch后面小括号当中只能是下列数据类型:
a. 基本数据类型: byte/short/char/int
b. 引用数据类型:String字符串、enum枚举类型 - swtich语句格式可以很灵活:前后顺序可以颠倒,而且break语句还可以省略。匹配到哪一个case就从哪一个位置向下执行,直到遇到了break或者整体结束为止。
- for 循环的初始化是在循环体内部,所以外部(大括号外)不能调用;而do···while循环和while的初始化都是在循环体的外部,所以在整体的大括号内都可以调用。
- do···while循环:无条件执行第一次循环体,即使我们将循环条件直接写成false,也依然会循环一次。这样的循环具有一定的风险性,因此初学者不建议使用do···while循环。
- for 循环流程:初始化 --> 条件判断 --> 循环体执行语句 --> 步进语句 --> 条件判断
- continue 关键词: 一旦执行,立即跳过当前次循环剩余内容,马上开始下一次循环。
for (int i= 0; i <= 10; i++) {
if (i == 4) {
continue; // 跳过当前次循环,马上开始下一次循环
}
System.out.println(i + "层到了。")
}
- 死循环的时候,输入ctrl+c (命令行运行时)即可中断循环。
方法
- 返回值类型必须和return语句返回的类型相同,
- 不能在return后面写代码,return意味着方法的结束,所有后面的代码永远不会执行,属于无效的代码。
- 方法的重载
- 定义: 在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
- 参数列表:个数不同,数据类型不同,顺序不同。println就是一个重载。
public static void open(){}
public static void open(int a){}
public void open(int a, int b){} //重复
public static void open(double a, int b){}
public static void open(int a, double b){} //重复
public void open(int i, double d){} // 重复
public static void OPEN(){}
public static void open(int i, int j){} //重复
数组
数组的初始化
- 动态初始化: 在创建数组的时候,直接指定数组当中的数据元素个数。
int[] arrayA = new int[3];
double[] arrayB = new double[10];
String[] arrayC = new String [5];
- 动态初始化可以进行拆分:
String[] arrayC;
arrayC = new String[5];
- 静态初始化: 在创建数组的时候,不直接指定数据个数的多少,而是直接将具体的数据内容进行指定。
int[] arrayA = int[] {5, 10, 20};
String arrayB = String[] {"Hello", "Java", "World!"};
- 静态初始化格式可以省略。
int[] arrayC = { 10, 20, 30 };
- 直接打印数组得到的是数组的内存地址哈希值。要访问数组具体元素格式为:数组名[i]; 请记住数组开始的索引值为0。
JVM的内存划分
- 栈(Stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。
- 堆(Heap) : 凡是new出来的东西,都在堆当中。
- 堆内存里面的东西都有一个地址值:16进制
- 堆内存中的数据,都有默认值。规则:
整数 | 0 |
---|---|
浮点数 | 0.0 |
字符 | ‘\u0000’ |
布尔 | false |
引用类型 | null |
- 方法区(Method Area) : 存储 .class 相关信息,包含方法的信息。
- 本地方法栈(Native Method Stack):与操作系统相关。
- 寄存器(pc Register):与CPU相关。
public class Demo01ArrayOne {
public static void main(String[] args){
int[] array = new int[3];
System.out.println(array);
}
}
- 以上程序的具体内存存储过程:
- 首先,在方法区中存储public static void main(String[] args)等方法信息.
- 然后压栈,将这些方法以及代码压入到栈(stack)当中去执行,但是new的数组在堆当中进行存储。
- 栈当中保存数组的地址值进行访问。
数组的遍历
public static void main(String[] args){
int[] arr = { 1, 2, 3, 4, 5 };
for(int i = 0; i < arr.length; i++ ){
System.out.println(arr[i]);
}
}
数组的反转
public class ArrayReverse{
public static void main(String[] args){
int[] arr = {1, 2, 3, 4, 5 };
for (int min = 0, max = arr.length - 1; min <= max; min++, max-- ){
int temp = arr[max];
arr[max] = arr[min];
arr[min] = temp;
}
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
}
- 数组可以作为方法的参数和返回值。
public static void main(String[] args){
int[] array = {1, 2, 3, 4, 5};
System.out.println(array);
PrintArray(array);
}
public static void PrintArray(int[] array){
System.out.println(array);
}
public static void calculate(int a, int b, int c){
''';
return array;
}
类与对象、封装、构造方法
类与对象
- Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想。这里的对象泛指现实中的一切事物,每种事物都具备自己的属性和行为。区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步去操作实现。
- 面向过程: 强调步骤。
- 面向对象: 强调对象。包含三大基本的特征:封装,继承,多态。
- 类:是一组相关属性和行为的集合。可以看成一类事物的模版,使用事物的属性特征和行为特征来描述该类事物。
对象:是一类事物的具体体现。对象是类的一个实例。
- 类是对一类事物的描述,是抽象的。
- 对象是一类事物的实例,是具体的。
- 类是对象的模版,对象是类的实体。以下是一个简单的练习:
public class Test01Phone{
public static void main(String[] args){
Phone one = new Phone();
p.brand = "Apple";
System.out.println("brand: "+p.brand);
p.call("me");
}
}
public class Phone{
//成员变量
String brand;
double price;
String color;
public void call(String name){
System.out.println("call "+name);
}
public void sendMessage(int name){
System.out.println("send "+name+" message");
}
}
- 类的使用内存简述。
a. 先在方法区存储,然后压栈。
b. 在栈中赋值等,然后new出来的类放在堆当中。包括累的成员变量和方法,但是方法保存的是方法的地址。
c. 但是在类的方法还是在栈中执行,执行完立马弹栈。 - 成员变量与局部变量的区别。
public class Car{
String color; //成员变量
public void drive(){
int speed = 80; //局部变量
System.out.println("时速:"+ speed);
}
}
- 位置不同:
成员变量:类中,方法外。
局部变量:方法中或者方法声明上(形式参数)。 - 作用范围不一样:
成员变量:类中。
局部变量:方法中。 - 初始化方法不同:
成员变量:有默认值。
局部变量:没有默认值。但是作为形参的时候,没有赋值,因为形参在方法调用的时候,必然会被赋值。 - 生命周期不同:
成员变量:随着对象的创建而存在,随着对象的消失而消失。
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失。
封装
- 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更加容易理解与维护,也加强了代码的安全性。
- 封装步骤:
a. 使用private关键字来修饰成员变量。
b. 对需要访问的成员变量,提供对应的一对getXxx方法、setXxx方法。 - private关键字:
a. private是一个权限修饰符,代表最小权限。
b. 可以修饰成员变量和成员方法。
c. 被private修饰后的成员变量和成员方法,只能在本类中才能访问。 - 代码演示:
package .....; //一定要保证是同一个包,不然不能去调用类
public class Person{
String name;
private int age;
public void show(){
System.out.println("My name is: "+name+", my age is "+ age);
}
public void setAge(int num){
if(num < 10 && num > 100){
System.out.println("Wrong age!");
} else{
age = num;
}
public int getAge(){
return age;
}
}
}
package .......;
public class Demo04Person{
public static void main(String[] args){
Student stu = new Student();
后面就是调用getAge(stu.getAge)去打印,setAge去修改
}
}
- 关于this关键字,当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,会优先使用局部变量。因此如果需要访问本类当中的成员变量,需要使用格式:this.成员变量名。
public class Student{
private int age;
private String name;
public student(){
System.out.println("My name is "+ name+" and my age is "+ "age"); //无参构造方法
}
public Student(String name, int age){
this.name = name;
this.age = age;
} //有参构造方法
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
- JavaBean是Java语言编写的一种标准规范。符合JB的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的set和get方法。