Skip to content

Commit 19b66db

Browse files
committed
线程
1 parent b80a874 commit 19b66db

31 files changed

Lines changed: 1206 additions & 35 deletions

src/com/yale/test/java/demo/JavaBean.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.beans.PropertyDescriptor;
77
/*
88
* JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。
9+
* https://www.liaoxuefeng.com/wiki/1252599548343744/1260474416351680
910
*/
1011
public class JavaBean {
1112
public static void main(String[] args) throws IntrospectionException {

src/com/yale/test/java/demo/Person.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
public class Person {
1919
public static void main(String[] args) {
2020
Person ps = new Person();
21-
Student stu = new Student();
21+
Student stu = new Student("Person类");
2222

2323
ps.testParam(stu);//传子类
2424

@@ -29,6 +29,19 @@ public static void main(String[] args) {
2929
Student stuTemp = (Student)tempP;//这行代码不会报错,因为tempP实际上就是一个Student对象,所以这里将父类强制转换为子类不会报错
3030
stuTemp.test();
3131
/**
32+
* 向下转型
33+
* 和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。例如:
34+
* Person p1 = new Student(); // upcasting, ok
35+
* Person p2 = new Person();
36+
* Student s1 = (Student) p1; // ok
37+
* Student s2 = (Student) p2; // runtime error! ClassCastException!
38+
* 如果测试上面的代码,可以发现:
39+
* Person类型p1实际指向Student实例,Person类型变量p2实际指向Person实例。在向下转型的时候,把p1转型为Student会成功,因为p1确实指向Student实例,
40+
* 把p2转型为Student会失败,因为p2的实际类型是Person,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。
41+
* 因此,向下转型很可能会失败。失败的时候,Java虚拟机会报ClassCastException。
42+
* 为了避免向下转型出错,Java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型:
43+
* instanceof实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为null,那么对任何instanceof的判断都为false。
44+
*
3245
* 向下转型不安全,可以使用instanceof判断一个实例究竟是不是某种类型
3346
* 如果一个引用变量为null,那么对任何instanceof的判断都为false。
3447
*/
@@ -57,6 +70,8 @@ public static void main(String[] args) {
5770

5871
Student temp = (Student)ps;//向下转型,这行代码会报错,因为ps这个对象实际上一个父类对象,所以不能将一个实际的父类对象强制转换为子类对象
5972
ps.testParam01(temp);//这里不强制会报错,但是强制调用testParam01方法有风险,如果testParam01方法内部调用了,子类特有的方法,代码运行就会报错
73+
74+
//继承是is关系,组合是has关系。
6075
}
6176

6277

src/com/yale/test/java/demo/PersonDemo.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public PersonDemo(String name) {
2626
* 如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在PersonDemo类中,定义多个hello()方法:
2727
* 这种方法名相同,但各自的参数不同,称为方法重载(Overload)。
2828
* 注意:方法重载的返回值类型通常都是相同的。
29+
* 注意:方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在Java程序中,出现这种情况,编译器会报错。
30+
* 如果方法签名相同,并且返回值也相同,就是Override。
31+
* 如果方法签名如果不同,就是Overload,Overload方法是一个新方法;
2932
*/
3033
public void hello() {
3134
System.out.println("Hello, world!");

src/com/yale/test/java/demo/Student.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,18 @@
99
* 注意,包名必须完全一致,包没有父子关系,com.apache和com.apache.abc是不同的包。
1010
*/
1111
public class Student extends Person {
12-
12+
13+
protected String services;
14+
15+
public String stuName;
16+
public String testStr2 = "调用的是父类的Student属性:testStr2";
17+
18+
public Student(String name) {
19+
this.stuName = name;
20+
}
21+
22+
private String testStr;
23+
1324
public void test() {
1425
System.out.println("方法的参数是子类,实际传参数时不能传父类,如果想传父类,就要把父类强制转换为子类后,再进行传参");
1526
System.out.println("将父类强制转换为子类传给方法时,代码运行时会有风险,因为方法内部有可能调用子类特有的方法.");
@@ -18,4 +29,32 @@ public void test() {
1829
public void superDemo() {
1930
System.out.println("Student类:中间的父类,");
2031
}
32+
33+
public String getTestStr() {
34+
return testStr;
35+
}
36+
37+
public void setTestStr(String testStr) {
38+
this.testStr = "调用的是父类的Student的testStr属性:" + testStr;
39+
}
40+
41+
public final String getStuName(){
42+
System.out.println("这个this是子类的还是父类的?" + this);
43+
System.out.println("当子类调用该方法时,stuName是父类的属性,即使子类也有名字相同的属性,那么问题来了,这里的this到底代表父类对象还是子类对象");
44+
return this.stuName;
45+
}
46+
47+
public void printServices() {
48+
/*
49+
* 如果子类也有一个public String services;属性,那么子类set父类就get不到了
50+
*/
51+
System.out.println("###############父类能获取到吗##############");
52+
System.out.println("子类set父类get:-->" + this.getServices());
53+
System.out.println("子类set父类get:-->" + this.services);
54+
System.out.println("################父类能获取到吗#############");
55+
}
56+
57+
private String getServices() {
58+
return this.services;
59+
}
2160
}

src/com/yale/test/java/demo/SuperDemo.java

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@
22

33
/*
44
* 如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final。用final修饰的类不能被继承
5+
* 在OOP的术语中,我们把Student称为超类(super class),父类(parent class),基类(base class),把SuperDemo称为子类(subclass),扩展类(extended class)。
6+
* 继承有个特点,就是子类无法访问父类的private字段或者private方法。
57
*/
68
public class SuperDemo extends Student{
79
public final String strss;//这里不初始化赋值,变量会报错,解决这个报错的办法是在构造方法里面给strss初始化赋值
810
public final String name = "用final修饰的字段在初始化后不能被修改";
11+
12+
public final static String strStatic = "";//用final static修饰的变量,必须直接初始化,否则编译报错
913

10-
//用final static修饰的变量,必须直接初始化,否则编译报错
11-
public final static String strStatic = "";//这里不初始化赋值,变量会报错,解决这个报错的办法是在构造方法里面给strss初始化赋值
12-
14+
private String testStr;
15+
public String testStr2 = "调用的是子类的SuperDemo属性:testStr2";
16+
public String stuName;// 注意:子类自动获得了父类的所有字段,严禁定义与父类重名的字段!
17+
1318
public SuperDemo(){
19+
super("Student类的stuName");
1420
strss = "";//这里不给strss初始化赋值,编译会报错
21+
this.stuName = "子类SuperDemo的stuName";
1522
}
1623
public SuperDemo(String name) {
24+
super(name);
1725
strss = "";//这里不给strss初始化赋值,编译一样会报错
18-
}
19-
20-
public static void main(String[] args) {
21-
SuperDemo.testStatic();//静态方法也可以被继承
22-
SuperDemo sd = new SuperDemo();
23-
sd.superDemo();
24-
//sd.name="121";这里会报错,因为name,是用final修饰的,并且JVM会针对final修饰的字段做优化,详情参考PerfmaDemo类.
25-
//并且用final修饰的属性,也不能提供set方法
26-
System.out.println();
26+
this.stuName = "子类SuperDemo的stuName";
2727
}
2828

2929
public void superDemo() {
@@ -42,6 +42,68 @@ public String getName() {
4242
}
4343

4444
// public void setName(String name){
45-
// this.name = name;
45+
// this.name = name; name是用final修改的,不能重新赋值了
4646
// }
47+
48+
49+
public String getTestStr() {
50+
return testStr;
51+
}
52+
public void setTestStr(String testStr) {
53+
this.testStr = "调用的是子类的SuperDemo的testStr属性:" + testStr;
54+
}
55+
56+
public void setServices(String services) {
57+
this.services = services;
58+
}
59+
60+
public static void main(String[] args) {
61+
SuperDemo.testStatic();//静态方法也可以被继承
62+
SuperDemo sd = new SuperDemo("test");
63+
sd.superDemo();
64+
System.out.println();
65+
System.out.println("子类的对象地址" + sd);
66+
System.out.println("这里输出的是子类的stuName:-》" + sd.stuName);
67+
System.out.println("这里获取的是父类的的stuName属性因为调的是父类getStuName的方法,所以要用父类的stuName属性:-->" + sd.getStuName());
68+
69+
//sd.name="121";这里会报错,因为name,是用final修饰的,并且JVM会针对final修饰的字段做优化,详情参考PerfmaDemo类.
70+
//并且用final修饰的属性,也不能提供set方法
71+
System.out.println();
72+
73+
sd.setServices("子类set父类get");
74+
75+
/*
76+
* 这里实际上设置的是父类的属性services,然后设置为被子类继承了,所以sd.services
77+
* 能取到值,你可以反编译看一下setServices这个方法
78+
*/
79+
System.out.println("子类的services属性:-->" + sd.services);
80+
sd.printServices();
81+
82+
System.out.println();
83+
System.out.println("***********************************");
84+
85+
/*
86+
* Student stu = new SuperDemo();
87+
* 这是因为SuperDemo继承自Student,因此,它拥有Student的全部功能。Student类型的变量,如果指向SuperDemo类型的实例,对它进行操作,是没有问题的!
88+
* 这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。
89+
* 向上转型实际上是把一个子类型安全地变为更加抽象的父类型:
90+
* 注意到继承树是SuperDemo > Student > Object,所以,可以把SuperDemo类型转型为Student,或者更高层次的Object。
91+
* 向下转型
92+
* 和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。例如:
93+
*/
94+
Student stu = new SuperDemo();
95+
stu.superDemo();
96+
97+
stu.setTestStr("测试");
98+
System.out.println("这里调用的是子类的getTestStr,所以打印的是子类的testStr属性->>:" + stu.getTestStr());//这里调用的子类的
99+
/*
100+
* 注意如果通过父类.属性调用,那么调用的就是父类的属性,
101+
* 如果通过get方法调用那调用的就是子类的属性
102+
*/
103+
System.out.println("……父类……->" + stu.testStr2);
104+
System.out.println();
105+
System.out.println("子类的对象地址" + stu);
106+
System.out.println("这里输出的是父类的:-》" + stu.stuName);
107+
System.out.println("这里获取的是谁的属性:因为调用的是父类的getStuName方法->" + stu.getStuName());
108+
}
47109
}

src/com/yale/test/java/fanshe/ClassForNameDemo.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package com.yale.test.java.fanshe;
22

33
class ForName {
4+
public ForName() {
5+
System.out.println("构造方法先执行还是,static块先执行");
6+
}
7+
//static属性和static代码块是按照代码的先后顺序执行的
8+
private static ForName forNam = new ForName();
49
static {
510
System.out.println("Class.forName相当于JVM加载类,加载类的时候会执行类的静态代码块");
611
System.out.println("不过JDBC那个,把类加载到JVM里面有什么用呢?又不用他,jdbc为啥必须用Class.forname???");
@@ -12,8 +17,12 @@ class ForName {
1217
}
1318
System.out.println("OracleDriver有啥用呢,又不用OracleDriver类上面的方法和属性");
1419
}
20+
private static ClassForNameDemo classForNameDemo = new ClassForNameDemo();
1521
}
1622
public class ClassForNameDemo {
23+
public ClassForNameDemo() {
24+
System.out.println("ClassForNameDemo构造方法先执行还是,static块先执行");
25+
}
1726
public static void main(String[] args) throws ClassNotFoundException {
1827
/**
1928
* Class类描述的是整个类的信息,在Class类中提供的forName()方法它所能处理的只是通过CLASSPATH配置的路径进行类的
@@ -31,6 +40,7 @@ public static void main(String[] args) throws ClassNotFoundException {
3140
* 而Class.forName完成了加载、验证、准备、解析和初始化
3241
*/
3342
Class.forName("com.yale.test.java.fanshe.ForName");//所以那个地方要用Class.forName,至于不用也行大家也说了SPI
43+
System.out.println();
3444
ForName fn = new ForName();//Class.forName和new对象的时候JVM才会加载这个类,并且执行类中的static块代码
3545
Class<?> cls = ForName.class;//这种叫静态加载类,静态加载类不会初始化类,把上面那个代码注释执行这个发现,上面的静态代码块没有被执行
3646
Class test = ForName.class.getClass();//这种叫静态加载类,静态加载类不会初始化类,这行代码也不能让JVM记载类,上面的静态代码块也不会被执行

src/com/yale/test/java/fanshe/ConstructorDemo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public static void main(String[] args) throws InstantiationException, IllegalAcc
6060
getDeclaredConstructors():获取所有Constructor。
6161
* 注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
6262
* 调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。
63+
* https://www.liaoxuefeng.com/wiki/1252599548343744/1264803033837024
6364
*/
6465
Class<?> per = PersonThir.class;
6566
//现在明确表示取的指定参数类型的构造方法

src/com/yale/test/java/fanshe/FiledDemo.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.yale.test.java.fanshe;
22

3+
import java.io.IOException;
4+
import java.lang.reflect.Constructor;
35
import java.lang.reflect.Field;
6+
import java.lang.reflect.InvocationTargetException;
7+
import java.lang.reflect.Modifier;
48

59
class FieldTest {
610
public String name;
@@ -41,9 +45,34 @@ public static void main(String[] args) throws ClassNotFoundException, NoSuchFiel
4145
* 但是使用scField.setAccessible(true);
4246
* 此外,setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。
4347
* 例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
48+
* https://www.liaoxuefeng.com/wiki/1252599548343744/1264803033837024
4449
*/
4550
scField.setAccessible(true);//设置为true就可以访问private属性
4651
scField.set(obj, "四中");//通过反射给FieldTe对象的属性设置值
4752
System.out.println("通过反射取的设置的属性:->" + scField.get(obj));
53+
54+
55+
Class.forName("java.lang.Runtime");
56+
Class<?> runtimeCls = Runtime.class;
57+
Constructor<?>[] conts = runtimeCls.getDeclaredConstructors();
58+
for (int i=0;i<conts.length; i++) {
59+
System.out.println("Runtime类的所有构造方法:" + conts[i]);
60+
System.out.println("Runtime类的所有构造方法(注意构造方法的getName方法):" + conts[i].getName());
61+
System.out.println("得到构造方法的修饰符public还是别的什么,返回的是数字:" + conts[i].getModifiers());
62+
int m = conts[i].getModifiers();
63+
if (Modifier.isPrivate(m)) {
64+
System.out.println("构造方法是私有的");
65+
conts[i].setAccessible(true);
66+
try {
67+
Runtime runtime = (Runtime)conts[i].newInstance(null);
68+
runtime.exec("notepad");
69+
System.out.println("可以通过反射获取Runtime对象吗?答案是可以的" + runtime);
70+
} catch (InvocationTargetException e) {
71+
e.printStackTrace();
72+
} catch (IOException e) {
73+
e.printStackTrace();
74+
}
75+
}
76+
}
4877
}
4978
}

src/com/yale/test/java/meiju/ColorEnum.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,28 @@
33
/*
44
* 使用enum定义的枚举类是一种引用类型。前面我们讲到,引用类型比较,要使用equals()方法,如果使用==比较,
55
* 它比较的是两个引用类型的变量是否是同一个对象。因此,引用类型比较,要始终使用equals()方法,但enum类型可以例外。
6-
* 这是因为enum类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==比较:
6+
* 这是因为enum类型的每个常量在JVM中只有一个唯一实例(单例),所以可以直接用==比较:
77
* 通过enum定义的枚举类,和其他的class有什么区别?
88
答案是没有任何区别。enum定义的类型就是class,只不过它有以下几个特点:
99
定义的enum类型总是继承自java.lang.Enum,且无法被继承;
1010
只能定义出enum的实例,而无法通过new操作符创建enum的实例;
1111
定义的每个实例都是引用类型的唯一实例;
1212
可以将enum类型用于switch语句。
13+
例如,我们定义的Color枚举类:
14+
public enum Color {
15+
RED, GREEN, BLUE;
16+
}
17+
编译器编译出的class大概就像这样:
18+
public final class Color extends Enum { // 继承自Enum,标记为final class
19+
// 每个实例均为全局唯一:
20+
public static final Color RED = new Color();
21+
public static final Color GREEN = new Color();
22+
public static final Color BLUE = new Color();
23+
// private构造方法,确保外部无法调用new操作符:
24+
private Color() {}
25+
}
26+
所以,编译后的enum类和普通class并没有任何区别。但是我们自己无法按定义普通class那样来定义enum,必须使用enum关键字,这是Java语法规定的。
27+
因为enum是一个class,每个枚举的值都是class实例,因此,这些实例有一些方法:
1328
*/
1429
enum ColorDemo {
1530
RED, GREEN, BLUE//这里实际上调用的是ColorDemo的无参构造方法,如果没有无参构造方法,这里必须传值,见Sex.java类

src/com/yale/test/java/meiju/Sex.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,25 @@ interface IColor {
88
* 从java1.5开始有了枚举
99
*/
1010
public enum Sex implements IColor{
11-
MAN("男"),WOMAN("女");//这行代码必须写在第一行,其实就是枚举类Sex的对象,这里实际上调用的是Sex的构造方法
11+
MAN("男","王"), WOMAN("女","张");//这行代码必须写在第一行,其实就是枚举类Sex的对象,这里实际上调用的是Sex的构造方法
1212

13+
private final String name;//注意种类虽然跟父类的Enum.class里面的属性一样,但是属性是不会覆盖父类的
1314
private final String value;//注意:枚举类的字段也可以是非final类型,即可以在运行期修改,但是不推荐这样做!
1415
//enum的构造方法要声明为private,字段强烈建议声明为final;
1516
//https://www.liaoxuefeng.com/wiki/1252599548343744/1260473188087424
16-
private Sex(String value){//枚举就是多例,构造方法绝对不能使用public
17+
private Sex(String value,String name){//枚举就是多例,构造方法绝对不能使用public
1718
this.value = value;
19+
this.name = name;
1820
}
1921

22+
// public final String name() {这个方法不能编译通过,因为这个name()方法在Enum.class类里面是final方法,但是可以用name属性
23+
// return "";
24+
// }
25+
26+
// public int ordinal() {这个方法也不能编译通过,因为这个ordinal()方法在Enum.class类里面是final方法
27+
// return 0;
28+
// }
29+
2030
public void print(){
2131
System.out.println("枚举类就是类多例模式的实现,所以枚举类不能用有公开构造方法.枚举类也可以有自己方法.");
2232
}
@@ -36,7 +46,7 @@ public static void main(String[] args) {
3646
System.out.println(Sex.MAN);
3747
System.out.println(Sex.WOMAN);
3848
//默认情况下,对枚举常量调用toString()会返回和name()一样的字符串。但是,toString()可以被覆写,
39-
//而name()则不行。判断枚举常量的名字,要始终使用name()方法,绝不能调用toString()!
49+
//而name()则不行,因为name()方法是父类Enum.class的final方法,子类是覆写不了的。判断枚举常量的名字,要始终使用name()方法,绝不能调用toString()!
4050
//枚举类可以应用在switch语句中。因为枚举类天生具有类型信息和有限个枚举常量,所以比int、String类型更适合用在switch语句中
4151
System.out.println(Sex.MAN.name() + "," + Sex.MAN.ordinal());
4252
for (Sex temp : Sex.values()) {

0 commit comments

Comments
 (0)