本文使用typora直接上传,由于没有设置图墙,图片无法显示。
如需笔记,可私信博主
1.基础知识
1.1Java语言概述
知识点 | 内容 | 注 |
---|---|---|
特点 | 跨平台性 | JVM(java virtual machine,java虚拟机) |
核心机制 | Java虚拟机(JVM) | |
垃圾收集机制 | Java还是可能出现内存泄漏、内存溢出问题 |
1.2JDK、JRE、JVM关系
名称 | 内容 |
---|---|
JDK | - Java开发工具包(Java Development Kit) - 包括:JRE、开发工具 - 开发工具:编译工具(javac.exe),打包工具(jar.exe) |
JRE | - Java运行环境(java runtime environment) - 包括:JVM、Java核心类库 - 不可开发,可以运行 |
JVM | - Java虚拟机(java virtual machine) |
1.3基础语法
1.3.1变量
1.3.1.1基本数据类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L6QOvdmI-1639810532177)(image-20211123205100215.png)]
注:
-
java中方法参数传递方式是按值传递。
如果参数是基本类型,传递的是基本类型的字面量值的拷贝。
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。
class basicKnowledge{ public void func(String s){ s="stupid"; } } public class basicKnowledgeTest { public static void main(String[] args){ basicKnowledge bk=new basicKnowledge(); String s="wangjunyi"; bk.func(s);//这里传递的是s的地址的拷贝值,该地址拷贝值指向了“wangjunyi”,但原地址没有 System.out.println(s); } }
-
为什么叫做引用数据类型:

执行
str="java";//赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。

1.3.1.1.1整型
整型 | 占用字节 | 表数范围 | 注 |
---|---|---|---|
byte | 1字节=8bit | -128~127 | |
short | 2字节 | [ − 2 15 , 2 15 − 1 ] [-2^{15},2^{15}-1] [−215,215−1] | |
int | 4字节 | [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31}-1] [−231,231−1] | |
long | 8字节 | [ − 2 56 , 2 56 − 1 ] [-2^{56},2^{56}-1] [−256,256−1] | long l1=14545424L; |
1.3.1.1.2浮点型
浮点型 | 占用字节 | 表数范围 | 注 |
---|---|---|---|
float | 4字节 | [-3.403E38,3.403E38] | float>long |
double | 8字节 | [-1.798E308,1.798E308] | Java浮点型常量默认为double |
1.3.1.1.2字符类型
字符类型 | 占用字节 | 编码 | 表现形式 | 特点 |
---|---|---|---|---|
char | 2字节 | Unicode编码 (一个字符可以表示一个字母/汉字/其他书面语) | 1.单引号:char c1=‘a’; 2.转义字符:char c2=’\t’ 3.直接用Unicode值(4位十六进制) char c3=’\u000a’ (’\n’) | - 可以进行运算 - 不可以为空 char c1=’’;//wrong |
- 1.3.1.1.3布尔型
boolean: true or false
1.3.1.2基本数据类型之间的转换
1.3.1.2.1自动类型转换
小范围->大范围:√
大范围->小范围:×
即:byte、char、short–>int–>long–>float–>double
char:
- byte、char、short三种变量进行运算时,结果为int类型
float f1=12.3F;//correct
float f2=12.3;//wrong,double->float
float f3=12.3+f1;//wrong,double->float
long l1=123456L;//correct
long l2=123456;//correct,int->long
byte b='c';
byte b1=b+1;//wrong,int->byte,整型常量默认int型
int i1=b+1;//correct
float f=12.3F;
double d1=12.2+f;//correct,浮点型常量默认double
1.3.1.2.2强制类型转换
()
1.3.1.3基本数据类型与String之间的转换
1.3.1.3.2String
- 引用数据类型
- 支持与其他类型(整数、浮点数)拼接
//支持拼接
String s1="wangjing",s2="NB";
String s=s1+s2;
System.out.println(s);
char c='a';
int num=10;
String str="hello";
System.out.println(c+num+str);//107hello
System.out.println(c+(num+str));//a10hello
System.out.println((c+num)+str);//107hello
System.out.println((str+num)+c);//hello10a
System.out.println(str+num+c);//hello10a
System.out.println('*'+'\t'+'*');//97,都是整型变量进行加和
System.out.println('*'+"\t"+'*');//* *,从左到右运算,字符串的拼接
System.out.println('*'+'\t'+"*");//53*,先整型加和再拼接
System.out.println('*'+('\t'+"*"));//* *
//String->int
String s="123";
int i1=parseInt(s);

1.3.1.4进制与进制之间的转换
0b/0B:二,十,0:八,0X/0x:十六
1.3.2关键字和保留字
1.3.2.1关键字
- 关键字所有都小写
1.3.2.2保留字
- 以后的Java版本可能使用的预备关键字
1.3.3标识符
合法标识符规则:

标识符命名规范:

注:
- java使用Unicode字符集,理论上中文也可以当作标识符
1.3.4运算符
1.3.4.1算术运算符
运算符 | 举例 | 说明 |
---|---|---|
/ | -8/5=-1 8/5=1 — 8/5.0=1.6 | 不是四舍五入 而是舍弃小数取整数 被除数和除数中有浮点数结果:double |
% | -12%5=-2 12%5=2 12%-5=2 -12%-5=-2 | 结果符号与被模数是一样的 |
+±- | 自增(减)1不会改变变量的数据类型 |
1.3.4.2赋值运算符
运算符 | 举例 | 说明 |
---|---|---|
+= -= /= *= | short s=1; s=s+2;//wrong; s+=2;//yes | 不会改变变量的数据类型 |
int i=1;
i*=0.1;//0,C++亦此
1.3.4.3比较运算符
1.3.4.4逻辑运算符
运算符 | 说明 |
---|---|
&逻辑与 | 如果&前面为false,后面内容还是照样执行 |
&&短路与 | 如果&&前面为false,则不执行后面的内容 |
|逻辑非 | 如果|前面是true,后面的内容照样执行 |
||短路非 | 如果|前面是true,后面的内容不执行了 |
1.3.4.5位运算符
- 操作的都是整型变量,是直接对整数的二进制每一位进行的运算


🥚

- A<<n:A*2^n,直到最高位变成1(突变负数)
- A>>n:A/2^n,(直到最高位变成1,突变负数)
1.3.4.6三元运算符
1.3.4.7运算符优先级

1.3.5程序流程控制
1.3.5.1switch-case
- 注意break;
- switch(整型表达式)
1.3.4.2带标签的break和continue
label1:for(int i=0;i<4;i++){
for(int j=i;j<4;j++){
System.out.print(j);
if(i==3)
break label1;
}
System.out.println();
}
/*
0123
123
23
3
*/
1.4数组
数据类型:引用数据类型
数组元素:既能是基本数据类型,也可以是引用数据类型
长度一旦确定,不能改变
1.4.1一维数组
1.4.1.1声明和初始化
int[] ids;//声明,可以把int[]当作类
ids=new int[]{1001,1002,1003,1004};//静态初始化:数组初始化和数组元素的赋值同时进行
String[] names=new String[5];//动态初始化:分开进行
1.4.1.2获取长度
//获取长度
//.length属性
System.out.println(names.length);
1.4.1.3数组的默认初始化值
类型 | 默认初始化值 |
---|---|
整型 | 0 |
浮点型 | 0.0 |
char型 | 0//不是‘0’,输出的话是空白 |
boolean型 | false |
引用数值类型(String,类,接口,数组) | null |
1.4.1.4数组的内存解析
- 内存的简化结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-reyZJNij-1639810532179)(image-20211202161808810.png)]
- 程序执行过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lZpm8bRO-1639810532179)(image-20211202162358777.png)]
栈空间没有变量指向0x12ab,垃圾回收机制在合适的时机进行回收
引用数据类型new时,改变的是地址,而不是改变指向的变量
1.4.2二维数组
1.4.2.1声明和初始化
//二维数组
//声明与初始化
int[][] arr1=new int[][]{{1,2,3},{4,5},{6,7,8}};//静态初始化,长度可以不一样
String[][] arr2=new String[3][2];//动态初始化
String[][] arr3=new String[3][];//动态初始化
int[] arr4[]=new int[][]{{1},{1,2},{1,3}};//静态初始化,也是正确的
1.4.2.2获取数组的长度
//获取数组的长度
System.out.println(arr1.length);//3
System.out.println(arr1[1].length);//4
1.4.2.3二维数组的默认初始化值
二维数组 | 外层元素a[] | 内层元素a[] [] |
---|---|---|
int[] [] | 地址值🚩 | 0(与一维数组相同) |
1.4.2.4二维数组的内存解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HIImjA8A-1639810532180)(image-20211202211656713.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jn0MFmtJ-1639810532180)(image-20211202211714156.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-syASysw2-1639810532180)(image-20211202211747849.png)]
1.4.3数组算法
1.4.3.1赋值
- random
double d=Math.random();//[0,1)之间的一个随机数
Random rand = new Random(512);//512:seed
int i=rand.nextInt();
double db=rand.nextDouble();
- arr2=arr1
int[] arr1=new int[]{3,5,6,1,7,8};
int[] arr2;
arr2=arr1;//arr2和arr1的关系:arr2与arr1地址相同,都指向堆空间中唯一的数组实体
1.4.3.2特征值(max,min,avg,sum)
1.4.3.3复制
//元素为基本数据类型
int[] arr2=new int[arr1.length];
for(int i=0;i<arr1.length;i++){
arr2[i]=arr1[i];
}
1.4.3.4反转
1.4.3.5查找
1.4.3.6排序
1.4.4Arrays工具类
- 操作数组的工具类
1.4.4.1方法

int[] arr1 =new int[]{1,2,4,3};
int[] arr2 = new int[]{1,4,2,3};
boolean b=Arrays.equals(arr1,arr2);
System.out.println(b);
System.out.println(Arrays.toString(arr1));
Arrays.sort(arr2);
for(int i=0;i<arr2.length;i++){
System.out.print(arr2[i]+" ");
}
System.out.println("\n"+Arrays.binarySearch(arr2,4));
//false
//[1, 2, 4, 3]
//1 2 3 4
//3
1.4.5数组的常见异常
- 索引越界ArrayIndexOutOfBoundsException
- 空指针NullPointerException
2.面向对象(类和对象设计 | 继承与多态)
2.1面向过程和面向对象
2.1.1面向对象三大主线
1.Java类及类的成员:属性、方法、构造器、代码块、内部类
2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)
3.其他关键字:this,super,static,final,abstact,interface,package,import
2.2Java语言基本元素:类(Class)和对象(Object\instance)
2.3类的结构:属性和方法
- field=属性=成员变量(=域=字段)
- method=(成员)方法=函数
- 创建类的对象=类的实例化=实例化类
2.3.1属性与局部变量的对比
**属性:**加载到堆空间中
**static属性:**方法区
**局部变量:**栈
2.4类和对象的创建
Person p1=new Person();
2.4.1类里多个对象的关系
Person p1=new Person();
p1.name="Tom";
p1.age=1;
Person p3=new Person();
p3=p1;
p3.name;//Tom
p3.age=10;
p1.age;//10->类为引用数据类型,p3=p1的含义是将p1的地址赋给了p3,p3新new出来的Person对象会通过垃圾回收机制回收
2.5对象
2.5.1对象的内存解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1t1lqBqq-1639810532181)(image-20211207194948240.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SL3aBBNk-1639810532181)(image-20211207195621879.png)]
2.5.1.1对象数组的内存解析
**注意:**引用类型的变量,只能存储两类值:null 或 地址值(含变量的类型)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7sVGC4i-1639810532181)(image-20211207211751108.png)]
2.5.2万事万物皆对象
- 在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
- 在涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象
2.5.3匿名对象
new Phone().sendEmail();//不给对象一个名字,用完即弃,只能调用一次
2.6方法
2.7.1方法的声明:权限修饰符
private\public\缺省\protected
2.7.2方法的重载(overload)
- “两同一不同”:同一个类,同一个方法名,列表参数不同(参数个数不同、参数类型不同)
- 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系
2.7.3可变个数的形参
- …可传一个、两个、多个
- (数据类型…变量名)
- 与同数据数组类型冲突,无法构成重载,就当作数组即可
public void show(String ... strs){
}
public static void main(String[] args){
Test test=new Test();
test.show("hello");//right
test.show("hello","world");//right
test.show();//notice!:right
}
2.7.4⭐方法参数的值传递机制
2.7.4.1关于变量的赋值
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值
- 如果变量是引用数据类型(类、数组、接口),此时赋值的是变量所保存的数据的地址值
2.7.4.2Java的实参如何传入方法
方法的形参的传递机制:值传递
- 形参是基本数据类型,将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
2.7.4.3一个好例子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yo3JUToG-1639810532182)(image-20211208205449591.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PvbpsSPm-1639810532182)(image-20211208205427393.png)]
2.7.5递归方法
2.7封装性
程序设计追求“高内聚、低耦合”
高内聚:类的内部数据操作曦姐自己完成,不允许外部干涉
低耦合:仅对外暴露少量的方法用于使用。
**封装性的设计思想:**把该隐藏的隐藏起来,该暴露的暴露出来
- getXxx(),setXxx()
2.7.1权限修饰符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5CGlLoE-1639810532182)(image-20211208223147182.png)]
- 在类的成员定义前,与C++不同
权限由小到大:
-
private
-
缺省
-
protected
-
public
注意:
- 4中权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
- 修饰外部类:缺省、public
2.7.2构造器
//权限修饰符+类名+(形参)
public Person();//注意和C++不同,有权限修饰符
2.8继承性
2.8.1基本概念
class A extents B{}
//A:subclass
//B:superclass
-
subclass extends superclass‘s 所有的属性、结构、方法,(构造器见后文)
-
**私有属性:**实际上获取到了,但是因为封装性的影响,不能直接调用,可以用过setAge(),getAge()获取和修改
-
子类可以额外定义自己的属性和方法
-
子类的范围要≥父类,不同于集合和子集
2.8.2java中关于继承性的规定
- Java中类的单继承性和多层继承性:一个类可以被多个子类继承,一个类只能有一个父类。允许多层继承
- 直接父类、间接父类
2.8.3Object类
- 如果没有显式地声明一个类地父类,此类继承与java.lang.Object类
- 所有类(除java.lang.Object类)都直接或间接继承java.lang.Object类,可以使用Object中的所有功能
2.8.3.1功能
2.8.3.1.1 equals()
-
==和.equals()
-
适用范围:
- 基本数据变量:值相等,没必要完全是同类型
- 引用数据类型:比较地址
== .euqals() 基本数据类型 值相等,没必要完全是同类型
int a=10;double b=10.0;a==b?//true
- 不和boolean比较- 这是一个方法
- 只针对类
- 不能适用于基本数据类型
- 可以用包装类引用数据类型 地址值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5TvBub2f-1639810532183)(image-20211212162445743.png)]- 在Object类中等价于==
- 在String,File,Data,包装类都重写了.equals的方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的实体内容是否相同Customer c1=new Customer("c1"); Customer c2=new Customer("c2"); String s1=new String("fsdfhs"); String s2=new String("fsdfhs"); System.out.println(c1.equals(c2));//false->地址值不同 System.out.println(s1.equals(s2));//true->重写了
- 注意比较String需要用equals而不是==
-
自定义类重写equals()
比较实体内容,而不是比较地址
class Person{ @override public boolean equals(Object obj){ if(this==obj){ return true; } if(obj instanceof Person){ //比较 } return false; } }
2.8.3.1.2 getClass()
2.8.3.1.3 toString()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k84eHu43-1639810532183)(image-20211212173750823.png)]
- 当我们输出一个对象得引用时,实际上就是在调用当前对象的toString()
- 像String,Data,File,包装类都重写了Object类中的toString方法
- 自定义类可以重写toString
public String toString(){
}
2.8.3.1.4 hashCode()
2.8.4包装类
2.8.4.1单元测试
Junit单元测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dyru259L-1639810532183)(image-20211212193614841.png)]
2.8.4.2使用
- 万物皆对象
- 使得基本数据类型就具有类的特征
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YaDy6R08-1639810532184)(image-20211212193650923.png)]
- 虚线框内:父类Number
2.8.4.3基本数据类型、包装类和String类之间的转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gfJcxwoB-1639810532184)(image-20211212194336623.png)]
public void Test1(){
//基本数据类型---->包装类
int num1=10;
Integer in1=Integer.valueOf(num1);
Integer in2=num1;
System.out.println(in1==num1);//true
System.out.println(in1.toString());//10
//包装类--->基本数据类型
System.out.println(in1.intValue());//10
Boolean b1=Boolean.valueOf("true123");//false
Boolean b2=Boolean.parseBoolean("true");//true
System.out.println(b1.booleanValue()?1:0);
//自动装箱
Integer in3=num1;
Boolean b3=true;
//自动拆箱
int num3=in3;
//基本数据类型--->String
int num4=1230;
String s2=num+"";
String s4=Integer.valueOf(num4).toString();
String s5=String.valueOf(num4);
//String--->基本数据类型
//包装器类.parseXXX(String s)
int num5=Integer.parseInt(s4);
boolean b4=Boolean.parseBoolean("true");
2.8.5方法重写
2.8.5.1定义
override/overwrite
-
重写:子类继承父类以后,可以对父类中同名同参数地方法进行覆盖操作
-
应用:重写之后,当创建子类对象的以后,通过子类对象调用子父类地同名同参数地方法是,实际执行的是子类重写父类的方法
2.8.5.2要求
- 重写:子类中重写的方法和父类中被重写的方法方法名和形参列表相同
- **权限修饰符:**子类重写的方法的权限修饰符 ≥ 父类中被重写的方法的权限修饰符
- 子类中不能重写父类中声明为private的方法
public class Person{
private void show(){
System.out.println("人");
}
}
package another
public class Student extends Person{
public void show(){//没有用,始终不会调用这个
System.out.println("学生");
}
}
public class StudentTest{
public static void main(String[] args){
Student s= new Student();
s.show();
}
}
//人
- 返回值类型
父类中被重写的方法 | 子类中重写的方法 |
---|---|
void | void |
A类 | A类或A的子类 |
基本数据类型 | 相同的基本数据类 |
- 抛出的异常类型
子类重写的方法抛出的异常类型 ≤ 父类重写的方法抛出的异常类型
2.8.5.3注意
2.8.6子类对象实例化过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xU867xGY-1639810532184)(image-20211212123322414.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzkaqTxc-1639810532185)(image-20211212123523278.png)]
- **从结果上看:**子类继承父类以后,就获取了父类中声明的属性或方法,创建子类的对象,在对空间中,就会加载所有父类中声明的属性。
- **从过程上看:**当我们通过子类的构造器创建子类对象时,我们一定会直接或间接地调用其父类地构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类地空参构造器位置。正因为加载过所有父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑进行调用。
- **注意:**虽然创建子类对象时,调用了父类的构造器,但是自始至终就只创建过一个对象
2.9多态性
2.9.1定义
Person p2=new Man();//父类的引用指向子类的对象,子类的对象赋给父类的引用
2.9.2使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BRkGQNxW-1639810532185)(image-20211212143541202.png)]
- 当调用子父类同名同参数的方法时,实际执行的时子类重写父类的方法 — 虚拟方法重用
- 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,;但在运行期,我们实际执行的是子类重写父类的方法。总结:编译看左边,执行看右边
- 使用前提:
- 类的继承关系
- 类的方法重写
2.9.3注意
public class Person{
int a=1;
}
package another
public class Student extends Person{
int a=2;
}
public class StudentTest{
public static void main(String[] args){
Person p1 = new Student;
System.out.println(p1.a);
}
}
//1->父类的
1.多态性不适合属性,属性编译和运行都看左边(superclass)
2.9.4重载和重写的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GDqibNw-1639810532185)(image-20211212143959691.png)]
2.9.5向下转型
用得少
2.9.5.1使用
有了对象的多态性以后,内存中实际上时加载了子类特有的属性和方法的,但是由于变量声明为父类型的,导致编译时只能调用父类中的属性和方法,子类特有的属性和方法不能调用
如何调用子类特有的属性和方法?(向下转型)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dM7uo2ls-1639810532185)(image-20211212150314281.png)]
Person p1=new Man();
Man m1=(Man)p1;//强转有风险
m1.earnMoney();//right
p1.earnMoney();//wrong
int a=m1.money;//right
int b=p1.money;//wrong
2.9.5.2问题
Person p1=new Person();
Man m1=(Man)p1;//wrong,小范围->大范围
2.9.6 关键字:instanceof
a instanceof A//:对象a是否是类A的实例,是->true
//为了避免再向下转型是出现异常,先进行instanceof
//的判断,一旦返回true,可以进行向下转型
2.9.7经典举例
在继承多态中:
1、对于方法的覆盖,new的谁就调谁,这就是多态。
2、对于成员变量的覆盖,this在哪个类就指向哪个类的成员变量,没有多态。
Man m1=new Man();
Person p1=m1;
System.out.println(p1==m1);//true,引用数据类型比较地址值
public class Person{
int count=1;
private void show(){
System.out.println(this.count);
}
}
package another
public class Student extends Person{
int count=2;
public void show(){//没有用,始终不会调用这个
System.out.println(this.count);
}
}
public class StudentTest{
public static void main(String[] args){
Student s= new Student();
System.out.println(s.count);//2
s.show();//2
Person p1=s;
System.out.println(p1.count);//1->属性无法被重写
p1.show();//2->方法被重写,位于子类中,对于成员变量的覆盖,this在哪个类就指向哪个类的成员变量,没有多态。
}
}
package basic;
public class Demo {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num);//->这里定义的是父类,而成员变量没有多态,所以即使你new的子类,依然指向父类的成员变量。
System.out.println(f.fun1());//->不解释了,就是多态。
f.show();
}
}
class Fu {
public String num = "父类成员变量";
public void show() {
System.out.println(this.num);//因为成员变量没有多态,所以this指向当前类对象的成员变量。
System.out.println(this.fun1());//因为方法有多态,所以this指向new对象的方法。
}
public String fun1() {
System.out.println(this.num);//因为成员变量没有多态,所以this指向当前类对象的成员变量。
return "父类调用";
}
}
class Zi extends Fu {
public String num = "子类成员变量";
public String fun1() {
System.out.println(this.num);//因为成员变量没有多态,所以this指向当前类对象的成员变量。
return "子类调用";
}
}
//父类成员变量
//子类成员变量
//子类调用
//父类成员变量
//子类成员变量
//子类调用
2.10关键字
2.10.1 this
2.10.1.1概念
- this表示当前对象,可以调用类的属性、方法和构造器
- this在方法内部使用,及这个方法所属对象的引用
- 在构造器内部使用,表示该构造器正在初始化的对象
2.10.1.1this在构造器中
public Person(){
this.name="abc";
}
public Person(int age){
this();//notice
this.age=age;
}
public Person(String description){
this(12);//notice
this.feat=description;
}
- this(形参列表)必须声明在当前构造器的首行,且最多调用一个其他的构造器
2.10.2 package
-
包也属于标识符
-
规范:小写
-
每.(点)一次,就代表一层文件目录
-
同一个包下,不能命名同名的接口、类;不同的包下,可以命名同名的接口、类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOFrS0BI-1639810532186)(image-20211208235938030.png)]
2.10.3 import
- 在源文件中显式地使用import结构导入指定包下的类、接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构,并列举出
- 可以使用"XXX.*"的方式,表示可以导入XXX包下的所有结构
- 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
- 如果使用的类或接口时本包下定义的,则可以省略import结构
- 如果导入不同包里面的类同名,使用时需要全类名(包.类)
- 使用”XXX.*“不可以调用XXX的子包,需要重新导入子包
2.10.4 super
2.10.4.1使用
- super:父类的…
- super可以修饰来调用:属性、方法和构造器
2.10.4.2 super调用构造器
super(形参列表)//必须声明在子类构造器的首行,一旦使用就不能再使用this(形参列表)
- 在构造器首行没有显式声明this(形参),super(形参),默认调用super()
public class Person{
Person(){
System.out.println("我无处不在")
}
}
package another
public class Student extends Person{
Student(){};
}
public class StudentTest{
public static void main(String[] args){
Student s= new Student();//子类构造器默认调用super(),所以需要父类具有空参构造器
}
}
//我无处不在
2.10.5 static
- 同一个类的所有对象共享同一个static数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7Z1xFkx-1639810532186)(image-20211212211227417.png)]
- static可以修饰:属性,方法,代码块,内部类
2.10.5.1使用static修饰属性
-
静态变量随着类的加载而加载,早于对象创建(实例化时),存在于方法区的静态域
-
只会加载一次,在内存中只有一份
Person.description;//直接调用类的静态变量
- 是否应该使用static:
- 属性时可以被多个对象所共享的,不会随着对象的不同而不同
2.10.5.2类变量和实例变量的内存解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VUZR1vdS-1639810532187)(image-20211213114921832.png)]
2.10.5.3使用static修饰方法
- 随着类的加载而加载,可以通过类.方法调用
- 静态方法中,只能调用静态的方法或属性(生命周期相同);非静态方法中,都可
- 不能使用this和super(this:当前对象而言,super也要基于当前对象的父类)
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L5yGI81l-1639810532187)(image-20211213115433069.png)]
- 是否应该使用static:
- 操作静态变量的方法,通常设置为static
- 工具类中的方法,习惯上声明为static的,笔记Math,Array,Collections
2.10.5.4单例设计模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RA9S6bdn-1639810532187)(image-20211213120013230.png)]
2.10.5.5使用static修饰代码块
2.10.5.6使用static修饰内部类
2.10.6 final
≈const
1.final可以修饰的结构:类、方法、变量
2.10.6.1final+类
- 此类不能被其他类继承
2.10.6.2final+方法
- 此方法不能被重写(不是重载)
2.10.6.3final+变量
- 变量不只是属性
- ->常量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyR8mlV6-1639810532187)(image-20211213184736407.png)]
o没有变,o的属性可以变
2.11 main方法的语法
- main程序入口
- main()也是一个普通的静态方法,可以调用
- main()形参也可以作为我们与控制台交互的方式(Scanner)
Public class Test{
int num1=1;
public static void main(String[] args){//不能调用除静态属性和静态方法之外的
System.out.println(num1);//wrong,非静态变量
}
}
class mianTest{
public static void main(String[] args){//可以被入口调用
}
}
//与控制台交互
Public class Test{
int num1=1;
public static void main(String[] args){
for(int i=0;i<args.length;i++){
System.out.print("..."+args[i]);
}
}
}
2.12抽象类和抽象方法
超级抽象的爸爸类
- abstract可以修饰的结构:类、方法
- 一旦abstract了,就不能实例化
2.12.1abstract+类
- 抽象类不能实例化
- 抽象类中一定有构造器,便于子类实例化时调用
- 开发中,都会提供抽象类的子类,让子类实例化,完成相关的操作
- 包含抽象方法的类,一定是抽象类;抽象类不一定有抽象方法。
abstract class Person{
}
2.12.2abstract+方法
- 没有方法体
- 非抽象的子类中需要实现父类中的所有抽象方法。
- 若子类重写了父类中的所有抽象方法,然后此子类才可以实例化
- 若子类没有重写了父类中的所有抽象方法,则此子类要么是抽象类要么报错
public abstract void eat();//没有括号
2.12.3 abstract的使用注意
- 不能用来修饰构造器、属性、私有方法、静态方法、final的方法、final的类
2.12.4 (匿名类)抽象类中构建匿名子类对象
public class Test(){
public static void main(String[] args){
Test t=new Test();
t.method(man);//非匿名类 非匿名对象
t.method(new Man());//非匿名类 匿名对象
Person p=new Person(){//匿名类 非匿名对象
public void eat(){
System.out.print("aa");
}
}
t.method(p);
t.method(new Person(){//匿名类 匿名对象
@Override
public void eat(){
}
});
}
public void method(Person p){
}
}
abstract class Person{
public abstract void eat();
}
class Man extends Person{
@override
public void eat();
}
2.12.5模板方法的设计模式
2.12.6练习
2.13接口interface
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEVQt267-1639810532188)(image-20211213194602867.png)]
2.13.1定义
- 接口使用interface定义
- 接口和类是并列的
- 接口中只能定义全局常量和公有抽象方法,不能有构造器,不能实例化
- 常量定义:可以省略public static,默认都是全局常量
- 方法定义:可以
- 类实现接口(implements)
- 如果实现类覆盖了接口中所有的抽象方法,则此类可以实例化
- 如果实现类没有覆盖接口中所有的抽象方法,此类仍为抽象类
- Java可以实现多个接口
- 接口与接口之间是多继承
- 接口体现多态性
public class InterfaceTest{
}
class Plane implements Flyable{
@Override
public void fly(){
}
@Override
public void eat(){
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED=7900;
int MAX_SPEED=7900;
//公有抽象方法
public abstract void fly();
void stop();
}
interface extents Flyable,aa,bb,cc{//接口的多继承
}
class beautifulBoy extends Person implements makeUp,dressUp{
}
2.13.2接口和抽象类
1 | 接口 | 抽象类 |
---|---|---|
2.14类的成员四:代码块
public class Person{
int age;
String name;
{
}//用来初始化类或对象
Person(){
System.out.println("我无处不在")
}
}
- 用来初始化类或对象
- 只能用static修饰或者不修饰
2.14.1静态代码块
- 内部可以有输出语句
- 随着类的加载而加载,只执行一次
- 可以用于对静态变量进行初始化
- 如果一个类中定义了多个静态代码块,按照声明的先后顺序执行
- 静态代码块执行优于非静态代码块
- 只能调用静态属性、方法
static{
}
2.14.2非静态代码块
- 内部可以有输出语句
- 随着对象的创建而加载,每创建一个对象,就执行一次
- 如果一个类中定义了多个非静态代码块,按照声明的先后顺序执行
- 都可以调用(静态、非静态、属性、方法)
{
}
2.14.3对属性可以赋值的位置
- 默认初始化
- 显式初始化
- 构造器中初始化
- 有了对象以后,通过对象.属性或对象.方法的方式,进行赋值
- 在代码块中赋值
2.14.3.1属性赋值的顺序
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.orderId);
}
}
class Order{
int orderId = 3;
{
orderId = 4;
}
}
//4
2.14.4⭐练习
- 由父及子,静态先行
- **有继承关系,类的加载顺序:**先加载父类,再加载子类
package com.atguigu.java3;
//总结:由父及子,静态先行
class Root{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root(){
super();
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid(){
super();
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg){
//通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:"
+ msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf(){
//通过super调用父类中有一个字符串参数的构造器
super("尚硅谷");
System.out.println("Leaf的构造器");
}
}
public class LeafTest{
public static void main(String[] args){
new Leaf(); //Root的静态初始化块-Mid的静态初始化块-Leaf的静态初始化块-Root的普通初始化块-Root的无参数的构造器-Mid的普通初始化块-Mid的无参数的构造器-Mid的带参数构造器,其参数值:尚硅谷-Leaf的普通初始化块-Leaf的构造器
System.out.println();
new Leaf();//Root的普通初始化块-Root的无参数的构造器-Mid的普通初始化块-Mid的无参数的构造器-Mid的带参数构造器,其参数值:尚硅谷-Leaf的普通初始化块-Leaf的构造器
}
}
/*
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:尚硅谷
Leaf的普通初始化块
Leaf的构造器
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:尚硅谷
Leaf的普通初始化块
Leaf的构造器
*/
package com.atguigu.java3;
class Father {
static {
System.out.println("11111111111");
}
{
System.out.println("22222222222");
}
public Father() {
System.out.println("33333333333");
}
}
public class Son extends Father {
static {
System.out.println("44444444444");
}
{
System.out.println("55555555555");
}
public Son() {
System.out.println("66666666666");
}
public static void main(String[] args) { // 由父及子 静态先行
System.out.println("77777777777");
System.out.println("************************");
new Son();
System.out.println("************************");
new Son();
System.out.println("************************");
new Father();
}
}
/*
11111111111
44444444444
77777777777
************************
22222222222
33333333333
55555555555
66666666666
************************
22222222222
33333333333
55555555555
66666666666
************************
22222222222
33333333333
*/
2.15类的成员五:内部类
不大用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BxZfnr0c-1639810532188)(image-20211213204845918.png)]
package basic;
public class InnerClass {
public static void main(String[] args){
//创建静态成员内部类
Person.Dog dog=new Person.Dog();
//创建非静态成员内部类--》先有对象
Person p= new Person();
Person.Bird bird=p.new Bird();
}
}
class Person{
int age;
String name;
//静态成员内部类
static class Dog{
public void show(){
}
}
//非静态成员内部类
class Bird{
String name;
public void sing(){
System.out.println(Person.this.age);//调用外部类的结构
}
public void displasy(String name){
System.out.println(name);//方法形参
System.out.println(this.name);//内部类属性
System.out.println(Person.this.name);//外部类属性
}
}
}
2.15.1 分类
- 成员内部类
一方面,作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰,非内部类不可以被static修饰
另一方面
-
可以定义属性、方法、构造器
-
可以被final(不能继承),abstract(不能调用)修饰
- 局部内部类(方法内,代码块内,构造器内)
2.15.2实例化成员内部类对象
public class InnerClass {
public static void main(String[] args){
//创建静态成员内部类
Person.Dog dog=new Person.Dog();
//创建非静态成员内部类--》先有对象
Person p= new Person();
Person.Bird bird=p.new Bird();//notice!
}
}
2.15.3区分调用外部类的结构
class Person{
String name;
//非静态成员内部类
class Bird{
String name;
public void sing(){
System.out.println(Person.this.age);//调用外部类的结构
}
public void displasy(String name){
System.out.println(name);//方法形参
System.out.println(this.name);//内部类属性
System.out.println(Person.this.name);//外部类属性
}
}
}
2.15.4局部内部类
public class cmp {
//返回一个实现了Comparable接口的类
public Comparable getComparable(){
class myComparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
return new myComparable();
}
}
2.16Java类的高级特性
2.16.1泛型
2.16.2Java的类加载机制
2.16.3反射机制
2.16.4注解
3.📕Java标准类库
3.1 String类
3.2StringBuffer类
3.3包装器类
3.4System类和Runtime类
3.5Math和Random类
3.6Date和Calendar类
3.8Set类
4.异常处理
4.1异常概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h19M9PPQ-1639810532188)(image-20211213214726168.png)]
4.2分类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thOIiKzs-1639810532189)(image-20211213215402794.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vlcZtBzY-1639810532189)(image-20211213215912426.png)]
体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uGNuO4SE-1639810532189)(image-20211213220548509.png)]
4.2.1编译时异常
提前准备
4.2.2运行时异常
遇到再说
4.3异常处理方式
4.3.1概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXW50c6v-1639810532189)(image-20211213222412351.png)]
- 抛:一旦抛出异常对象,其后的代码不再执行
- 抓:可以理解为异常处理的两种方式:①try-catch-finally ②throws
4.3.2机制一:try-catch-finally块
4.3.2.1try-catch
- try出现异常位置之后的代码不再执行
- 如果catch成功处理,try_catch后面的代码正常执行
- 常用的异常对象处理方式:①String getMessage() ②printStackTrace()
- 在try结构中声明的变量,除了try块就不能用了
try{//可能出现的异常
}
catch(异常类型一 变量名1){//处理异常的方式1
System.out.println(e.getMessage());
}
catch(异常类型二 变量名2){
System.out.println(e.getStackTrace());
}
finally{//一定会执行的代码
}
4.3.2.2finally的使用
- finally是可选的
- finally一定会被执行:即使catch中又出现异常,try中有return语句,catch中有return语句
- 什么东西需要写进finally:
public void testMethod(){
int num = method();
System.out.println(num);
}
public int method(){
try{
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
return 2;
}finally{
System.out.println("我一定会被执行");
return 3;
}
}
public void test2(){
FileInputStream fis = null;//写在外面,防止finally中fis看不到
try {
File file = new File("hello1.txt");
fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {//嵌套
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.3.3机制二:throws + 异常类型
往上抛
- throws + 异常类型卸载方法的声明处
- 一旦方法体执行出现异常,在异常代码处生成异常类的对象,此对象满足throws后异常类型时,就会被抛出。
- 异常代码后续代码不执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kOmmZFmW-1639810532190)(image-20211213231246920.png)]
4.4编译时异常和运行时异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eqt1Q40w-1639810532191)(image-20211213230240169.png)]
4.5重写方法异常抛出的规则
方法重写的规则之一:
-
子类重写的方法抛出的异常 ≤ 父类被重写的方法抛出的异常
public class OverrideTest { public static void main(String[] args) { OverrideTest test = new OverrideTest(); test.display(new SubClass()); } public void display(SuperClass s){//注意这里的形参是父类 try { s.method(); } catch (IOException e) { e.printStackTrace(); } } } class SuperClass{ public void method() throws IOException{ } } class SubClass extends SuperClass{ public void method()throws FileNotFoundException{ } }
4.6如何选择哪种方式处理异常
-
如果父类被重写的方法没有throws方式处理异常,子类重写的方法也不可(-》try-catch-finally)
-
执行的方法a中,先后调用了另外的几个方法,这几个方法是递进关系执行的。
我们建议这几个方法:throws
a:try-catch-finally
4.7手动抛出异常对象:throw
4.8自定义异常
//自定义异常
/*
* 如何自定义异常类?
* 1. 继承于现有的异常结构:RuntimeException 、Exception
* 2. 提供全局常量:serialVersionUID
* 3. 提供重载的构造器
*
*/
public class MyException extends Exception{//继承
static final long serialVersionUID = -7034897193246939L;//全局常量
public MyException(){
}
public MyException(String msg){//重载的构造器
super(msg);
}
}
package com.atguigu.java2;
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");//抛出自定义异常对象
//错误的
// throw new String("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
4.9练习
//写出程序结果
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally {
System.out.println("用A方法的finally");
}
}
static void methodB() {
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
methodB();
}
}
5.多线程
5.1概述
5.1.1程序 进程 线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBexxaA9-1639810532192)(image-20211214010138654.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mXtClnps-1639810532193)(image-20211214010449367.png)]
5.1.2单核CPU与多核CPU
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mB49X2vR-1639810532193)(image-20211214010808619.png)]
5.1.3并行和并发
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6ut5ZAk-1639810532194)(image-20211214010833342.png)]
5.1.4多线程的优点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31dFaLhR-1639810532196)(image-20211214011141766.png)]
5.1.5多线程的使用情景
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2yuUE5f-1639810532196)(image-20211214011546623.png)]
5.2⭐创建多线程的方式
5.4.1f方式一:继承Thread类
5.4.1.1java.lang.Thread类的特性
-
每个线程通过Thread对象的run()方法完成操作
run()方法的主体:线程体
-
通过该Thread对象的start()方法来启动线程,而非直接调用run()
5.4.1.创建 过程
* 多线程的创建,方式一:继承于Thread类
* 1. 创建一个继承于Thread类的子类
* 2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
* 3. 创建Thread类的子类的对象
* 4. 通过此对象调用start()
//1. 创建一个继承于Thread类的子类
class MyThread extends Thread {
//2. 重写Thread类的run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3. 创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
t1.start();
//问题一:我们不能通过直接调用run()的方式启动线程。
// t1.run();
//问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException
// t1.start();
//我们需要重新创建一个线程的对象
MyThread t2 = new MyThread();
t2.start();
//如下操作仍然是在main线程中执行的。
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");
}
}
}
}
- start():①启动当前线程 ② 调用当前线程的run()
- 不可以还让已经start()的线程去再次执行
5.4.2方式二:实现Runnable接口
5.4.3两种创建方式的对比
5.3线程生命周期
5.4线程的安全问题(线程的互斥)
5.5⭐线程的同步
5.6死锁
6.📕GUI图形界面程序设计
7.I/O流
8.📕网络通信
9.📕JSP与Servlet | JDBC
5.多线程
5.1概述
5.1.1程序 进程 线程
[外链图片转存中…(img-KBexxaA9-1639810532192)]
[外链图片转存中…(img-mXtClnps-1639810532193)]
5.1.2单核CPU与多核CPU
[外链图片转存中…(img-mB49X2vR-1639810532193)]
5.1.3并行和并发
[外链图片转存中…(img-N6ut5ZAk-1639810532194)]
5.1.4多线程的优点
[外链图片转存中…(img-31dFaLhR-1639810532196)]
5.1.5多线程的使用情景
[外链图片转存中…(img-Q2yuUE5f-1639810532196)]
5.2⭐创建多线程的方式
5.4.1f方式一:继承Thread类
5.4.1.1java.lang.Thread类的特性
-
每个线程通过Thread对象的run()方法完成操作
run()方法的主体:线程体
-
通过该Thread对象的start()方法来启动线程,而非直接调用run()
5.4.1.创建 过程
* 多线程的创建,方式一:继承于Thread类
* 1. 创建一个继承于Thread类的子类
* 2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
* 3. 创建Thread类的子类的对象
* 4. 通过此对象调用start()
//1. 创建一个继承于Thread类的子类
class MyThread extends Thread {
//2. 重写Thread类的run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3. 创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
t1.start();
//问题一:我们不能通过直接调用run()的方式启动线程。
// t1.run();
//问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException
// t1.start();
//我们需要重新创建一个线程的对象
MyThread t2 = new MyThread();
t2.start();
//如下操作仍然是在main线程中执行的。
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");
}
}
}
}
- start():①启动当前线程 ② 调用当前线程的run()
- 不可以还让已经start()的线程去再次执行