JAVA SE

前言

每次比完赛之后都说要开始学JAVA,结果都是下次一定。其实大学的时候接触过一段时间的java,但也只是停留在基本的一些语法和用法。工作之后花在安全上的时间越来越少。再此,专门开个贴,重新学习和认识JAVA。来陪我一起度过在区县交流的日子。那之前都是会有一个计划,比如一天学多少,看多少章节的书,看多少小时的视频。这次我想更没规律一点,用兴趣和精力来驱动。

第一阶段

JAVA SE 、JAVA EE、JDK、JRE、JVM相关概念

java基础,也称为java SE,基础语法和特性。java EE , 企业级开发环境,比如用于web开发。

跨平台性(JVM) ,JVM:java virtual machine JVM类似于一个虚拟的计算机,具有指令集并使用不同的存储区域。

JDK=JRE+JAVA开发工具集(例如:java javac javadoc)

JRE(java runtime enviroment)=JVM+Java SE标准类库(JAVA核心类库)

1
2
3
test.java // 源文件
javac test.java //将test.java 编译成 test.class (也成为字节码文件)
java test.class //运行test文件,实际是在JVM上运行

JAVA开发注意事项

1.java源文件以.java为扩展名,源文件的基本组成部分是类(class)

2.java应用程序的执行入口是main()方法。它有固定的书写格式: public static void main(String[] args){….}

3.一个源文件中最多只能有一个public类。其他类的个数不限。

4.如果源文件包含一个public类,则文件名必须按该类名命名!

5.一个源文件中最多只能有一个public类。其他类的个数不限。也可以将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法。

重新认识转义

1
2
3
4
5
\t 制表符: 像表格一样字段间搞出一些空隙, 比如 上海\t北京  , 输出就是  上海      北京 
\r :就是把光标移到最前面,比如 上海\r是个大城市北京天津,输出就是 是个大城市北京天津
\n 换行:光标移动到下一行同一位置。
测试发现\r\n 和 \n 在输出控制台的效果是一样的。
原因:现代终端(包括命令行、IDE终端、网页中的控制台等)为了用户体验,会自动将 \n 解释为 \r\n 的功能。

注释

1
2
3
4
5
6
7
8
9
10
11
12
13
// : 单行注释

/* */ :多行注释

文档注释:
/**
*@author
*
*
*/

javadoc -d d:\\temp -author -version comment2.java
javadoc -d 目录 -xx -yy zz.java

编码

1
2
3
4
5
ASCII编码(1个字节),最多可以表示256个字符,但ASCII码只用了128个
unicode(unicode编码表 固定大小的编码,使用两个字节来表示字符,字母和汉字统一都是占用两个字节,这样浪费空间)
utf-8(编码表,大小可变的编码,字母使用1个字节,汉字使用3个字节,它可以使用1-6个字节)
gbk(可以表示汉字,而且范围广,字母使用1个字节,汉字2个字节)
可以算出每个编码文件大小。

数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
基本数据类型:
1.数值型:
整数类型,存放整数,byte:1字节 short:2字节 int:4字节 long:8字节
浮点类型:float:4字节 double:8字节
2.字符型:char:2字节,单引号包裹
char c1='a'
char c2='\t'
char c3='韩'
char c4=97 //输出为a,在java中,char的本质是一个整数,默认输出时,是unicode码对应的字符。
char a2='a'
System.out.println(int(a2)) //输出为97
System.out.println('a'+10)//输出为107
char类型是可以进行运算的。
3.布尔型:bool:1字节

String //多个字符,注意S是大写,双引号包裹

引用数据类型:
类(class)
接口(interface)
数组([])

+号的使用:
如果两边都是数值,输出为和.
如果一边为字符串,那就是拼接.
运算顺序是从左往右的.
eg:
System.out.println(100+3) //输出为103
System.out.println("hello"+100) //输出为hello100
System.out.println(100+3+"hello")//输出为103hello
System.out.println("hello"+100+3)//输出为hello1003

自动数据类型转换

数据类型转换.png

按照这个规则,char可以自动转为int,比如 int num=’a’ //输出的num值为97 。但是精度大的不能自动转为精度小的。

细节:

1.有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。

int n= 10; float d1=n+1.1; //报错,因为1.1是double类型。 改成 double d1=n+1.1;即可。或者改成float d1=n+1.1F;

2.当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据类型时,就会报错,反之就会进行自动类型转换。

3.(byte,short)和char之间不会相互自动转换。

4.byte,short,char 他们三者可以计算,在计算时

java类的组织形式

java类组织形式.png

一个在线看java api文档的网站matools 可以按照这个结构来检索我们想要查找的类以及对应的一些说明。

JVM的内存对象存在形式:

image-20251118200558409

image-20251119204125325

类和对象的内存分配机制

1.栈:一般存放基本数据类型(局部变量)

2.堆:存放对象(Cat cat ,数组等)

3.方法区:常量池(常量,比如字符串),类加载信息

4.示意图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Java创建对象的流程简单分析:

Person p=new Person();

p,name="jack";

p,age=10;

1.先加载Person类信息(属性和方法信息,只会加载一次)

2.在堆中分配空间,进行默认初始化(看规则)

3.把地址赋给p , p就指向对象

4.进行指定初始化,比如p.name = "jack" , p.age=10 ;

方法重载

JAVA的一个类里面,允许方法重名,这个方法重载和C++里面的重载思想很像。不过要求:形参列表类型不一样,数量不一样,对返回类型无要求

我一开始写了个错误案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class OverLoad01{
public static void main(String[] args)
{
System.out.println("Overload");

int a=1;
int b=2;
double c=3.14;
calculate01(a,b);
calculate01(a,a,b);
calculate01(a,c);
}

public void calculate01(int n1,int n2)
{
int sum=n1+n2;
System.out.println(sum);
}

public void calculate01(int n1 ,int n2 ,int n3)
{
int sum=n1+n2+n3;
System.out.println(sum);
}

public void calculate01(int n1,double n2)
{
double sum=n1+n2;
System.out.println(sum);
}

}

这样运行是会报错的,static静态方法属于类本身,不需要new 一个对象就可以调用,如果我不把calculate01声明为 static,那么不能直接调用,所以,要把calculate都改成static :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 class OverLoad01{
public static void main(String[] args)
{
System.out.println("Overload");
int a=1;
int b=2;
double c=3.14;
calculate01(a,b);
calculate01(a,a,b);
calculate01(a,c);
}

public static void calculate01(int n1,int n2)
{
int sum=n1+n2;
System.out.println(sum);
}

public static void calculate01(int n1 ,int n2 ,int n3)
{
int sum=n1+n2+n3;
System.out.println(sum);
}

public static void calculate01(int n1,double n2)
{
double sum=n1+n2;
System.out.println(sum);
}

}

或者再写个类,从这个类new一个对象去调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

public class OverLoad01{
public static void main(String[] args)
{
System.out.println("Overload");

int a=1;
int b=2;
double c=3.14;
CalCulate test=new CalCulate();
System.out.println("hello ");
test.calculate01(a,b);
test.calculate01(a,a,b);
test.calculate01(a,c);
}
}
class CalCulate
{
public void calculate01(int n1,int n2)
{
int sum=n1+n2;
System.out.println(sum);
}

public void calculate01(int n1 ,int n2 ,int n3)
{
int sum=n1+n2+n3;
System.out.println(sum);
}

public void calculate01(int n1,double n2)
{
double sum=n1+n2;
System.out.println(sum);
}
}

构造器

简单的一个demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Construct01{
public static void main(String[] args)
{
System.out.println("just a test");
Person p =new Person("zhangshan",25);
System.out.println(p.name+"\n"+p.age);
}
}
class Person{
public String name;
public int age;
public Person(String pname,int page)
{
name=pname;
age=page;
}
}

细节:

1.构造器没有返回值,并且方法名和类名一样。

2.所有的类都有默认缺省的构造器,只要不显示定义,就会调用默认的构造器。

3.构造器并没有创建对象,而是创建对象时,会调用构造器来完成初始化。注意逻辑顺序

4.java的构造器也可以进行重载,需要遵循的原则和重载一致。

this关键字

this的出现首先很好的解决了上面构造器里面形参和属性一样导致的歧义问题,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Construct01{
public static void main(String[] args)
{
System.out.println("just a test");
Person p =new Person("zhangshan",25);
System.out.println(p.name+"\n"+p.age);
}
}
class Person{
public String name;
public int age;
public Person(String name,int age)
{
name=name;
age=age;
}
}

这样跑起来会有点小问题,这样输出的是null和0,即属性的默认值。局部变量赋值给局部变量,指代不明确。所以需要用到this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Construct01{
public static void main(String[] args)
{
System.out.println("just a test");
Person p =new Person("zhangshan",25);
System.out.println(p.name+"\n"+p.age);
}
}
class Person{
public String name;
public int age;
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
}

这样输出就是正常的了。

1.this关键字可以用来访问本类的属性、方法、构造器

2.this用于区分当前类的属性和局部变量

3.访问成员方法的语法:this.方法名(参数列表)

4.this不能在类定义的外部使用,只能在类定义的方法中使用。

包可以理解成一个文件夹,包的三大作用

1.可以区分同名的类

2.当类很多时,可以更好的管理类

3.控制访问范围。

package 包名 , 声明类属于该包

import 包名 , 导入XX包

java常用的包:

1
2
3
4
java.lang.*  //默认导入
java.util.*
java.net.*
java.awt.*

包导入:

1
2
3
import java.util.Scanner //只导入java.util包下的Scanner

import java.util.* //导入 java.util包下的所有类

demo:

目录结构

1
2
3
4
5
6
7
8
src 
-com
--use
---Test.java
--xiaoming
---Dog.java
--xiaoqiang
---Dog.java
1
2
3
4
5
6
7
8
9
10
11
//com.use包下的Test.java
package com.use; //声明Test类属于com.use这个包,package只能有一条,一个类不可能同时属于几个包吧。
import com.xiaoming.Dog; //引入了com.xiaoming包中的Dog类
public class Test {
public static void main(String[] args) {
Dog dog=new Dog();
System.out.println(dog);
com.xiaoqiang.Dog dog2=new com.xiaoqiang.Dog();
System.out.println(dog2);
}
}
1
2
3
4
5
6
7
//com.xiaoming下的Dog.java
package com.xiaoming;
public class Dog {
public static void main(String[] args){
System.out.println("xiaoming's Dog");
}
}
1
2
3
4
5
6
7
8
9
//com.xiaoqiang下的Dog.java
package com.xiaoqiang;
public class Dog {

public static void main(String[] args) {
System.out.println("xiaoqiang's dog");
}
}

访问修饰符

java提供四种访问控制修饰符号,用于控制方法和属性

  • public
  • protected
  • 默认
  • private
访问级别 访问控制修饰符 同类 同包 子类 不同包
公开 public
受保护 protected ×
默认 没有修饰符 × ×
私有 private × × ×

封装

面向对象三大特征:封装、继承和多态

下面是一个封装的demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.hspedu.encap;
public class Encapsulation01 {
public static void main(String[] args){
Person a=new Person("my0n9ssssss",12,4000.52);
a.setName("aaaaaaaaaaa");
}
}

class Person{
public String name;
private int age;
private double salary;
public Person(String name,int age,double salary){
this.name=name;
this.age=age;
this.salary=salary;
}
public void setName(String name){
if(name.length()>=2&&name.length()<=6){
this.name=name;
}
else {
System.out.println("input name is unnormal!");
}

}
public void setAge(int age){

if(age>120)
{
System.out.println("age is beyond!");
}
else{
this.age=age;
}

}
public void setSalary(double salary){
this.salary=salary;
}

public String getName(){
return this.name;
}
public int getAge(){
return this.age;

}
public double getSalary(){
return this.salary;
}
}

继承

复用一些属性和方法。

父类必须有一个默认的空参数的构造函数,比如public parent (){} ,不然子类继承的时候会报错,如下案例:

1
2
3
4
5
6
7
8
9
父类:
public class Parent{
public String name;
int age ;
}
子类:
public class child extends Parent{

}

super的使用,指代父类属性,显示调用父类构造函数,显示调用父类的方法。

调用父类属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Animal {
protected String name = "Animal";
}
class Dog extends Animal {
protected String name = "Dog";
public void displayNames() {
System.out.println("子类的 name: " + this.name);
System.out.println("父类的 name: " + super.name);
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.displayNames();
}
}

调用父类构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Parent {
int x;
Parent(int x) {
this.x = x;
}
}
class Child extends Parent {
int y;
Child(int x, int y) {
super(x); // 调用父类构造函数
this.y = y;
}
@Override
public String toString() {
return "Child{" + "x=" + x + ", y=" + y + '}';
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child(10, 20);
System.out.println(child.toString());
}
}

调用父类方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal {
public void move() {
System.out.println("Animal is moving");
}
}
class Dog extends Animal {
@Override
public void move() {
super.move(); // 调用父类的 move 方法
System.out.println("Dog is moving");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.move();
}
}

多态

方法或对象具有多种形态。

方法的多态:重写和重载可以体现。

对象的多态:要理解编译类型和运行类型,举个例子,Animal类是父类;Cat、Dog是子类。

Animal a= new Cat() ,左边的Animal就是编译类型,右边的Cat就是运行类型。调用的方法就是Cat里面的方法,而编译类型在定义之后,是不会改变的,运行类型是可以变的。

比如: a=new Dog() ,那么此时的Dog就是运行类型了。再次调用的方法,就可以调用Dog类的方法了。如果再对a进行重新赋值,那么就是a=new Cat(),这会儿再次调用方法,就可以调用Cat类的方法了。编译不可变,但是运行是可以变化的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//master.java
package com.hspedu.extend.poly;
public class Master {
public String name;
public int age;
public void Feed(Animal animal,Food food){

System.out.println(animal.name+" eat "+food.name);

}
public static void main(String args[]){

System.out.println("Poly test!");
Master master = new Master();
Animal dog=new Dog("xiaohuang","dog");
Animal cat=new Cat("xiaohua","cat");
Food rice=new Rice("rice","rice");
Food meat=new Meat("meat","meat");
master.Feed(dog,meat);
master.Feed(cat,rice);
}
}
//Animal.java
package com.hspedu.extend.poly;
public class Animal {
public String name;
public Animal(String name){
this.name = name;
}
}
//Food.java
package com.hspedu.extend.poly;
public class Food {
public String name;
public Food(String name){
this.name = name;
}
}
//Dog.java
package com.hspedu.extend.poly;

public class Dog extends Animal{
public String catagory;
public Dog(String name,String catagory){
super(name);
this.catagory = catagory;
}
public String getCatagory(){
return catagory;
}
public String getName(){
return name;
}
}
//Cat.java
package com.hspedu.extend.poly;
public class Cat extends Animal {
public String catagory;
public Cat(String name,String catagory){
super(name);
this.catagory = catagory;
}
public String getCatagory(){
return catagory;
}
public String getName(){
return name;
}
}
//Rice.java
package com.hspedu.extend.poly;
public class Rice extends Food{
public String catagory;
public Rice(String name,String catagory){
super(name);
this.catagory = catagory;
}
}