Skip to content

Commit 25280e1

Browse files
committed
Java
1 parent 5c282a8 commit 25280e1

File tree

6 files changed

+1396
-1
lines changed

6 files changed

+1396
-1
lines changed

src/CyberSecurity/CTF/1-CTF_WEB.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,3 +714,13 @@ O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
714714
上传即可
715715

716716
![image-20240813220240174](./img/1-CTF_WEB/image-20240813220240174.png)
717+
718+
## 7. Git泄露-log
719+
720+
先用githacker工具跑一便,就有了该网站的.git文件夹
721+
722+
![image-20240901095525585](./img/1-CTF_WEB/image-20240901095525585.png)
723+
724+
然后查看log信息,对比两次提交即可
725+
726+
![image-20240901095711570](./img/1-CTF_WEB/image-20240901095711570.png)
107 KB
Loading
69.2 KB
Loading

src/develop/Java/3_CoreClass.md

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,328 @@ class Person {
650650

651651
## 枚举类
652652

653+
### enum
654+
655+
为了让编译器能自动检查某个值在枚举的集合内,并且,不同用途的枚举需要不同的类型来标记,不能混用,我们可以使用`enum`来定义枚举类:
656+
657+
```java
658+
// enum
659+
public class Main {
660+
public static void main(String[] args) {
661+
Weekday day = Weekday.SUN;
662+
if (day == Weekday.SAT || day == Weekday.SUN) {
663+
System.out.println("Work at home!");
664+
} else {
665+
System.out.println("Work at office!");
666+
}
667+
}
668+
}
669+
670+
enum Weekday {
671+
SUN, MON, TUE, WED, THU, FRI, SAT;
672+
}
673+
```
674+
675+
注意到定义枚举类是通过关键字`enum`实现的,我们只需依次列出枚举的常量名。
676+
677+
和`int`定义的常量相比,使用`enum`定义枚举有如下好处:
678+
679+
首先,`enum`常量本身带有类型信息,即`Weekday.SUN`类型是`Weekday`,编译器会自动检查出类型错误。例如,下面的语句不可能编译通过:
680+
681+
```java
682+
int day = 1;
683+
if (day == Weekday.SUN) { // Compile error: bad operand types for binary operator '=='
684+
}
685+
```
686+
687+
其次,不可能引用到非枚举的值,因为无法通过编译。
688+
689+
最后,不同类型的枚举不能互相比较或者赋值,因为类型不符。例如,不能给一个`Weekday`枚举类型的变量赋值为`Color`枚举类型的值:
690+
691+
```java
692+
Weekday x = Weekday.SUN; // ok!
693+
Weekday y = Color.RED; // Compile error: incompatible types
694+
```
695+
696+
这就使得编译器可以在编译期自动检查出所有可能的潜在错误。
697+
698+
### enum的比较
699+
700+
使用`enum`定义的枚举类是一种引用类型。 引用类型比较,要使用`equals()`方法,如果使用`==`比较,它比较的是两个引用类型的变量是否是同一个对象。因此,引用类型比较,要始终使用`equals()`方法,但`enum`类型可以例外。
701+
702+
这是因为`enum`类型的每个常量在JVM中只有一个唯一实例,所以可以直接用`==`比较:
703+
704+
```java
705+
if (day == Weekday.FRI) { // ok!
706+
}
707+
if (day.equals(Weekday.SUN)) { // ok, but more code!
708+
}
709+
```
710+
711+
### enum类型
712+
713+
通过`enum`定义的枚举类,和其他的`class`有什么区别?
714+
715+
答案是没有任何区别。`enum`定义的类型就是`class`,只不过它有以下几个特点:
716+
717+
- 定义的`enum`类型总是继承自`java.lang.Enum`,且无法被继承;
718+
- 只能定义出`enum`的实例,而无法通过`new`操作符创建`enum`的实例;
719+
- 定义的每个实例都是引用类型的唯一实例;
720+
- 可以将`enum`类型用于`switch`语句。
721+
722+
#### name()
723+
724+
返回常量名,例如:
725+
726+
```java
727+
String s = Weekday.SUN.name(); // "SUN"
728+
```
729+
730+
#### ordinal()
731+
732+
返回定义的常量的顺序,从0开始计数,例如:
733+
734+
```java
735+
int n = Weekday.MON.ordinal(); // 1
736+
```
737+
738+
改变枚举常量定义的顺序就会导致`ordinal()`返回值发生变化。例如:
739+
740+
```java
741+
public enum Weekday {
742+
SUN, MON, TUE, WED, THU, FRI, SAT;
743+
}
744+
```
745+
746+
747+
748+
```java
749+
public enum Weekday {
750+
MON, TUE, WED, THU, FRI, SAT, SUN;
751+
}
752+
```
753+
754+
的`ordinal`就是不同的。如果在代码中编写了类似`if(x.ordinal()==1)`这样的语句,就要保证`enum`的枚举顺序不能变。新增的常量必须放在最后。
755+
756+
有些童鞋会想,`Weekday`的枚举常量如果要和`int`转换,使用`ordinal()`不是非常方便?比如这样写:
757+
758+
```java
759+
String task = Weekday.MON.ordinal() + "/ppt";
760+
saveToFile(task);
761+
```
762+
763+
但是,如果不小心修改了枚举的顺序,编译器是无法检查出这种逻辑错误的。要编写健壮的代码,就不要依靠`ordinal()`的返回值。因为`enum`本身是`class`,所以我们可以定义`private`的构造方法,并且,给每个枚举常量添加字段:
764+
765+
```java
766+
// enum
767+
public class Main {
768+
public static void main(String[] args) {
769+
Weekday day = Weekday.SUN;
770+
if (day.dayValue == 6 || day.dayValue == 0) {
771+
System.out.println("Work at home!");
772+
} else {
773+
System.out.println("Work at office!");
774+
}
775+
}
776+
}
777+
778+
enum Weekday {
779+
MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);
780+
781+
public final int dayValue;
782+
783+
private Weekday(int dayValue) {
784+
this.dayValue = dayValue;
785+
}
786+
}
787+
```
788+
789+
这样就无需担心顺序的变化,新增枚举常量时,也需要指定一个`int`值。
790+
791+
默认情况下,对枚举常量调用`toString()`会返回和`name()`一样的字符串。但是,`toString()`可以被覆写,而`name()`则不行。我们可以给`Weekday`添加`toString()`方法:
792+
793+
```java
794+
// enum
795+
public class Main {
796+
public static void main(String[] args) {
797+
Weekday day = Weekday.SUN;
798+
if (day.dayValue == 6 || day.dayValue == 0) {
799+
System.out.println("Today is " + day + ". Work at home!");
800+
} else {
801+
System.out.println("Today is " + day + ". Work at office!");
802+
}
803+
}
804+
}
805+
806+
enum Weekday {
807+
MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");
808+
809+
public final int dayValue;
810+
private final String chinese;
811+
812+
private Weekday(int dayValue, String chinese) {
813+
this.dayValue = dayValue;
814+
this.chinese = chinese;
815+
}
816+
817+
@Override
818+
public String toString() {
819+
return this.chinese;
820+
}
821+
}
822+
```
823+
824+
覆写`toString()`的目的是在输出时更有可读性。
825+
826+
### switch
827+
828+
最后,枚举类可以应用在`switch`语句中。因为枚举类天生具有类型信息和有限个枚举常量,所以比`int`、`String`类型更适合用在`switch`语句中:
829+
830+
```java
831+
// switch
832+
public class Main {
833+
public static void main(String[] args) {
834+
Weekday day = Weekday.SUN;
835+
switch(day) {
836+
case MON:
837+
case TUE:
838+
case WED:
839+
case THU:
840+
case FRI:
841+
System.out.println("Today is " + day + ". Work at office!");
842+
break;
843+
case SAT:
844+
case SUN:
845+
System.out.println("Today is " + day + ". Work at home!");
846+
break;
847+
default:
848+
throw new RuntimeException("cannot process " + day);
849+
}
850+
}
851+
}
852+
853+
enum Weekday {
854+
MON, TUE, WED, THU, FRI, SAT, SUN;
855+
}
856+
```
857+
858+
加上`default`语句,可以在漏写某个枚举常量时自动报错,从而及时发现错误。
859+
860+
## record类
861+
862+
Java 14开始,引入了新的`Record`类。我们定义`Record`类时,使用关键字`record`。把上述`Point`类改写为`Record`类,代码如下:
863+
864+
```java
865+
// Record
866+
public class Main {
867+
public static void main(String[] args) {
868+
Point p = new Point(123, 456);
869+
System.out.println(p.x());
870+
System.out.println(p.y());
871+
System.out.println(p);
872+
}
873+
}
874+
875+
record Point(int x, int y) {}
876+
```
877+
878+
仔细观察`Point`的定义:
879+
880+
```java
881+
record Point(int x, int y) {}
882+
```
883+
884+
把上述定义改写为class,相当于以下代码:
885+
886+
```java
887+
final class Point extends Record {
888+
private final int x;
889+
private final int y;
890+
891+
public Point(int x, int y) {
892+
this.x = x;
893+
this.y = y;
894+
}
895+
896+
public int x() {
897+
return this.x;
898+
}
899+
900+
public int y() {
901+
return this.y;
902+
}
903+
904+
public String toString() {
905+
return String.format("Point[x=%s, y=%s]", x, y);
906+
}
907+
908+
public boolean equals(Object o) {
909+
...
910+
}
911+
public int hashCode() {
912+
...
913+
}
914+
}
915+
```
916+
917+
除了用`final`修饰class以及每个字段外,编译器还自动为我们创建了构造方法,和字段名同名的方法,以及覆写`toString()`、`equals()`和`hashCode()`方法。
918+
919+
换句话说,使用`record`关键字,可以一行写出一个不变类。
920+
921+
和`enum`类似,我们自己不能直接从`Record`派生,只能通过`record`关键字由编译器实现继承。
922+
923+
### 构造方法
924+
925+
编译器默认按照`record`声明的变量顺序自动创建一个构造方法,并在方法内给字段赋值。那么问题来了,如果我们要检查参数,应该怎么办?
926+
927+
假设`Point`类的`x`、`y`不允许负数,我们就得给`Point`的构造方法加上检查逻辑:
928+
929+
```java
930+
public record Point(int x, int y) {
931+
public Point {
932+
if (x < 0 || y < 0) {
933+
throw new IllegalArgumentException();
934+
}
935+
}
936+
}
937+
```
938+
939+
注意到方法`public Point {...}`被称为Compact Constructor,它的目的是让我们编写检查逻辑,编译器最终生成的构造方法如下:
940+
941+
```java
942+
public final class Point extends Record {
943+
public Point(int x, int y) {
944+
// 这是我们编写的Compact Constructor:
945+
if (x < 0 || y < 0) {
946+
throw new IllegalArgumentException();
947+
}
948+
// 这是编译器继续生成的赋值代码:
949+
this.x = x;
950+
this.y = y;
951+
}
952+
...
953+
}
954+
```
955+
956+
作为`record`的`Point`仍然可以添加静态方法。一种常用的静态方法是`of()`方法,用来创建`Point`:
957+
958+
```java
959+
public record Point(int x, int y) {
960+
public static Point of() {
961+
return new Point(0, 0);
962+
}
963+
public static Point of(int x, int y) {
964+
return new Point(x, y);
965+
}
966+
}
967+
```
968+
969+
这样我们可以写出更简洁的代码:
970+
971+
```java
972+
var z = Point.of();
973+
var p = Point.of(123, 456);
974+
```
975+
976+
977+

0 commit comments

Comments
 (0)