课程 --》 【韩顺平 Java】 https://www.bilibili.com/video/BV1fh411y7R8/?p=8&share_source=copy_web&vd_source=8977f681475280eda810fba7f418ae06
一、基础
1)编程思想
Java概述
- 历史
- 特点
- Java运行机制
- JDK
- 转义字符
- Java开发规范
【.java文件中的每一个class编译后,都会对应生成一个.class文件】
- JavaAPI
- 注释
- 单行 //
- 多行 /* */
- 文档 /** */
-
变量
- 数据类型
- 变量基本使用
- 数据类型转换
运算符
- 运算符介绍
- 算术
- 关系
- 逻辑
- 赋值
- 三元
- 优先级
- 二进制
- 位运算符
控制结构
- 顺序
- 分支(if else switch)
- 循环(for,while,do while)
- break
- continue
- return
数组,排序,查找
- 一维数组
下标从0开始编号



//在仅声明但是没有分配内存空间情况下调用数组会空指针报错
//------------------------------1.动态初始化----------------------
//先声明数组
//数据类型[] 数组名;
//数据类型 数组名[];
int a [];
//再分配空间
//数组名 = new 数据类型[];
a = new int[];
//声明数组并分配内存空间
//数据类型[] 数组名 = new 数据类型[大小];
//数据类型 数组名[] = new 数据类型[大小];
int[] b = new int[];
//创建数组,名字为a,能存放5个int
int[] a = new int[5]
//-------------------------------2.静态初始化------------------------
//double类型的数组,名字是sum
doubel[] sum = {1,2,3,4,5,6,7};
//--------------------------------3.数组赋值机制------------------------------
//基本数据类型,复制赋值
int n1 = 10;
int n2 = n1;
n2 = 80; //结果:n1 = 10, n2 = 80
//数组,内存地址赋值
int[] a = {1,3,5,7,8,9};
int[] b = a;
b[0] = 10; //结果:a[0] = 10, b[0] = 10
//------------------------------4.数组操作-------------------------
//访问数组
int i = sum[5] //i=6;
//数组长度:数组名.length
sum.length;
//遍历数组
for(int i = 0; i < sum.length; i++){
sout(sum[i]);
}
//数组拷贝
int[] a1 = {1,3,5,7,8,9};
int[] a2 = new int[a1.length];
for(int i = 0; i < sum.length; i++){
a2[i] = a1[i];
}
//数组反转
int[] a1 = {11,22,33,44,55,66};
int temp = 0;
int len = a1.length;
for(int i = 0; i < len/2; i++){
temp = a1[len-1-i];
a1[len-1-i] = a1[i];
a1[i] = temp;
}
- 二维数组
数据类型[][] 变量名 = new 数据类型[][]
数据类型[] 变量名[] = new 数据类型[][]
数据类型 变量名[][] = new 数据类型[][]
int[][] arr = {{1,2,3},
{0,0,0},
{3,2,1}}
//杨辉三角形
public static void main(String[] args) {
int[][] arr = new int[10][];
for(int i = 0; i<arr.length; i++){
arr[i] = new int[i+1];
for (int j = 0; j<arr[i].length;j++){
if(j == 0 || j == arr[i].length-1){
arr[i][j] = 1;
}else{
arr[i][j] = arr[i-1][j]+ arr[i-1][j-1];
}
}
}
for(int i = 0; i<arr.length; i++){
for(int j = 0; j<arr[i].length; j++){
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
}

- 排序


//冒泡排序基础
int[] arr = {88,87,51,12,47,13,56};
int temp = 0;
for(int j = 0; j<arr.length-1;j++){
for (int i = 0; i < arr.length-j-1;i++){
temp = arr[i+1];
if(arr[i]>arr[i+1]){
arr[i+1] = arr[i];
arr[i] = temp;
}
}
}
for(int n =0;n<arr.length;n++){
System.out.println(arr[n]+"\t");
}
- 顺序查找
思路:输入一个内容,遍历数组并逐个匹配内容
- 二分查找
思路:在有序列表中,判断输入的值和中间的值哪个比较大,将数组数据分成两部分
面向对象
- 类与对象




class Person{
}
public static void main(String[]args){
Person p; //声明对象cat
p = new Person(); //创建对象
}
- 克隆对象
//思路
public class Main {
public static void main(String[] args) {
A a = new A();
a.age = 15;
a.name = "aabb";
a.price = 150;
A a2 = a.copy(a);
System.out.println(a2.age);
}
}
class A {
int age ;
String name ;
int price;
public A copy(A a){
A a2 = new A();
a2.age = a.age +15 ;
a2.name = a.name;
a2.price = a.price;
return a2;
}
}
- 成员方法

//定义方法
public 返回数据类型 方法名(形参列表){
方法体语句;
return 返回值;
}
//void表示没有返回值
public void ...
- 成员方法传参机制
- 基本数据类型:传递值
- 引用类型:传递内存地址
- 方法内创建的对象,若没有return此对象,则在方法结束后会被堆内存回收
- 递归

参数传入引用类型变量时,因为传入的是同一个内存地址,就会共享引用类型的数据

//---------------------打印问题----------------------
public class Main {
public static void main(String[] args) {
A a = new A();
a.re(4);
}
}
class A {
public void re(int n){
if (n>2){
re(n-1);
}
System.out.println(n);
}
}
//重复调用同一个方法,因此会先执行递归到最后的方法下方的语句
//即:
public void re(int n){
if (n>2){
public void re(int n){
if (n>2){
re(...);
}
//re(4)内被调用,即执行新增的方法re(3),优先于re(4)执行
System.out.println(n);
};
}
//re(4)最后执行
System.out.println(n);
}
//---------------------阶乘问题----------------------
public class Main {
public static void main(String[] args) {
A a = new A();
System.out.println(a.mu(4));
}
}
class A {
public int mu(int n){
if(n==1){
return 1;
}else {
return mu(n-1) * n;
}
}
}
汉诺塔
public class Main {
public static void main(String[] args) {
D d = new D();
d.move(10,'1','2','3');
System.out.println(d.i);
}
}
class D {
int i = 0;
public void move(int n , char a, char b, char c){
if(n==1){
System.out.println(a+"-->"+c);
i++;
}else {
move(n-1 , a, c, b);
System.out.println(a+"-->"+c);
move(n-1, b, a, c);
i++;
}
}
}
- overload
-
方法重载的介绍和好处
-
- 可变参数
-
可变参数基本概念 -
public int sum (int ... nums){ int res = 0; for(int i ; i< nums.length 'i++){ res += nums[i]; } return res; }
-
可变参数细节 //可变参数要放在形参的最后,不允许有多个可变参数 public void fun(String str,int ... nums){ }
-
- 作用域
-
作用域介绍 -
作用域细节 -
作用域注意事项
-
- 构造器
-
构造器介绍 -
构造器理解 -
构造器细节 -
构造器细节 -
public class construction01{ public static void main (String[]args){ Person p1 = new Person ("jack",18); Person p2 = new Person ("jack"); } } class Person { String name = ""; int age = 0; public Person(Sting pname , int page){ name = pname; age = page; } public Person(Sting pname){ name = pname; } }
-
- 创建对象流程分析
-
class Person{ int age = 40; String name; public Person(String n ,int a ){ name = n; age = a; } } public class const{ public ststic void main (String [] args){ Person p1 = new Person("jack",20) } } /* Person p1 = new Person("jack",20) 1.方法区加载person类 2.堆内存开劈空间保存对象,初始化属性,再属性赋值:age = 40; 3.构造器开始初始化,常量池开辟空间ox0011,保存"jack"; name赋值ox0011地址,age赋值20 4.对象赋值给p1 */
-
- this
-
this使用细节 -
//在构造器中访问另一个构造器 class T { //构造器中使用this public T(){ //注意:访问构造器语法:this(参数列表); 必须放在方法体的第一条 this("jack",20); } public T(String name , int age){ } }
-
- 包
-
包的作用和语法 -
包的理解 -
包的命名规范 -
常用的包 -
如何引入包 -
注意细节
-
- 访问修饰符
-
四种修饰符 -
访问范围
-
- 封装
-
封装介绍
-
- 继承
- 多态
- super
- overwrite
- 子类重写父类方法
- Object类详解
- 断点调试
小项目
2)编程能力
面向对象高级
- 类变量和类方法
-
静态变量可以解决的问题 - 类变量:类中的对象共享
-
类变量简介 -
类方法简介
-
- 理解main方法语法
-
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(i+ args[i]);
}
-
- 代码块
-
代码块简介 -
代码块理解 -
代码块的调用顺序优先于构造器
-
代码块注意事项1,静态代码块
-
-
代码块注意事项2,静态代码块 - 多个静态代码块或静态属性,方法;则按照定义的顺序调用
-
代码块注意事项3,静态代码块
-
- 单例设计模式
-
单例模式介绍 -
//饿汉式:一般使用单例模式的对象都是重量级对象 //对象还没使用,但是类加载的时候对象已经创建好了 //若后续也没有使用,则造成资源浪费 public class Cat { public static void main(String[] args) { Dog dog = Dog.getInstance(); } } class Dog{ private String name; private static Dog dog = new Dog("旺财"); /* * 如果保障只能创建一个对象 * 1.构造器私有化 * 2.在类的内部直接创建static对象,static属性 * 3.提供一个static方法,返回对象 * */ private Dog(String name){ this.name = name; } public static Dog getInstance(){ return dog; } }
-
//饿汉式:一般使用单例模式的对象都是重量级对象 //对象还没使用,但是类加载的时候对象已经创建好了 //若后续也没有使用,则造成资源浪费 //懒汉式:使用到该对象时,判断对象是否已创建,未创建再去创建 public class Cat { public static void main(String[] args) { Dog dog = Dog.getInstance(); } } class Dog{ private String name; private static Dog dog ; /* * 如果保障只能创建一个对象 * 1.构造器私有化 * 2.在类的内部直接创建static对象,static属性 * 3.提供一个static方法,返回对象 * */ private Dog(String name){ this.name = name; } public static Dog getInstance(){ if(dog == null){ dog = new Dog("旺财"); } return dog; } }
-
单例设计饿汉式,懒汉式区别
-
- final关键字
- 调用被final static一起修饰的变量,不会导致类的加载
-
//被final static一起修饰的变量,不会导致类的加载 class AA { public final static int i = 100 ; static{ System.out.print("静态代码块"); } } public class Main{ public static void main (String[] args){ System.out.print(AA.i); } }
- 抽象类
-
抽象类介绍 -
抽象类细节1 -
抽象类可以有已实现方法
-
抽象类细节2 -
抽象方法不可被 private , final,static修饰,这三个关键字与重写相违背
- 接口
- 内部类
- 局部内部类(有类名,定义在方法或代码块中)
- 匿名内部类(没有类名)
- 只是用一次的对象,可以使用匿名内部类
-
class Outer{//外部类 private int outer_i = 0; private void pri_m(){} public void mether(){ //------------------------基于接口的匿名内部类---------------------------- //需求: //1.想使用接口AA,并创建对象 //2.传统方式:写一个类,实现接口,创建对象 Animal people = new People(); Animal cat = new Cat(); people.eat(); cat.eat(); //但是需求是IA、IA2类只是用一次,往后再不使用,则浪费资源 //因此可以使用匿名内部类来简化开发 //animal的编译类型:Animal //animal的运行类型:匿名内部类,类名由系统分配 -Outer$1 /* 底层: Animal animal = new Animal(){...}; -- 相当于 -- class Outer$1 implements Animal{ @Override public void eat() { System.out.println("匿名内部类重写eat方法"); } }; */ //jdk底层在创建匿名内部类Outer$1,立刻就创建了Outer$1实例,并把地址返回给animal //匿名内部类只能生成一个实例,实例可以多次调用 Animal animal = new Animal(){ @Override public void eat() { System.out.println("匿名内部类重写aa方法"); } }; animal.eat(); //---------------------------------------------------------------- //----------------------------基于类的匿名内部类------------------------ /* 分析: 1.father的编译类型 Father 2.father的运行类型 Outer$2 底层: Father father = new Father("jack"){...}; -- 相当于 -- class Outer$2 extend Animal{...} 同时"jack"会传递给Father的构造器 */ Father father = new Father("jack"){ @Override public void test() { int i1 = outer_i; //基于类的匿名内部类,可以直接访问外部类的私有变量 pri_m(); //基于类的匿名内部类,可以直接访问外部类的私有方法 System.out.println("匿名内部类重写了Father.test()"); } }; father.test(); //---------------------------------------------------------------- //----------------------------基于抽象类的匿名内部类------------------------ Plant plant = new Plant() { @Override public void grow() { System.out.println("重写父类Plant的grow()"); } }; plant.grow(); } } interface Animal { public void eat(); } class People implements Animal { @Override public void eat() { System.out.println("People实现接口,重写aa()方法"); } } class Cat implements Animal { @Override public void eat() { System.out.println("Cat实现接口,重写aa()方法"); } } class Father{ private int i = 100; public Father(String name) { } public void test(){ } } abstract class Plant{ public abstract void grow(); } public class note { public static void main(String[] args) { Outer outer = new Outer(); outer.mether(); } } class Outer{//外部类 private int outer_i = 0; private void pri_m(){} public void mether(){ Animal animal = new Animal(){ int i1 = outer_i; //基于接口的匿名内部类,可以直接访问外部类的私有变量 //pri_m(); //基于接口的匿名内部类,因为接口中没有定义该方法,不可以直接访问外部类的私有方法 @Override public void eat() { System.out.println("匿名内部类重写aa方法"); } }; animal.eat(); Father father = new Father("jack"){ @Override public void test() { int i1 = outer_i; //基于类的匿名内部类,可以直接访问外部类的私有变量 pri_m(); //基于类的匿名内部类,可以直接访问外部类的私有方法 System.out.println("匿名内部类重写了Father.test()"); } }; father.test(); Plant plant = new Plant() { int i1 = outer_i; //基于抽象类的匿名内部类,可以直接访问外部类的私有变量 //pri_m(); //基于抽象类的匿名内部类,因为抽象类中没有定义该方法,不可以直接访问外部类的私有方法 @Override public void grow() { System.out.println("重写父类Plant的grow()"); } }; plant.grow(); } } interface Animal { public void eat(); } class People implements Animal { @Override public void eat() { System.out.println("People实现接口,重写aa()方法"); } } class Cat implements Animal { @Override public void eat() { System.out.println("Cat实现接口,重写aa()方法"); } } class Father{ private int i = 100; public Father(String name) { } public void test(){ } } abstract class Plant{ public abstract void grow(); } public class note { public static void main(String[] args) { Outer outer = new Outer(); outer.mether(); } }
- 匿名内部类的应用
//匿名内部类的应用 /* 传统方法实现接口是创建一个类实现接口,但是该类只调用一次则会浪费资源 */ interface Inter_a { void show(); } public class Note2 { public static void main(String[] args) { f1(new Inter_a() { @Override public void show() { System.out.println("把匿名内部类直接当参数写入"); } }); } public static void f1(Inter_a ia ){ ia.show(); } }
- 成员内部类(没有static)
-
class Outerr{ private int i = 100; public void f1(){ System.out.println("Outer的f1()"); } class Innerr{ public void f1(){ //成员内部类调用外部类的方法可以使用:Outerr.this.f1(); Outerr.this.f1(); System.out.println("Innerr的f1方法"); } public Innerr getInnerrInstance(){ return new Innerr(); } } } public class Note2 { public static void main(String[] args) { Outerr outer = new Outerr(); //外部其他类,使用成员内部类的三种方式 //第一种 outer.new Innerr();相当于把 new Innerr() 当做是Outerr的成员 //属于一种语法 Outerr.Innerr inner = outer.new Innerr(); System.out.println(inner.getClass()); // class Outerr$Innerr //第二种 在外部类中,编写一个方法,可以返回Innerr的对象 Outerr.Innerr gii = inner.getInnerrInstance(); //成员内部类方法与外部类重名,则就近原则 inner.f1(); } }
- 静态内部类(有static)
-
class Outerr{ private int i = 100; private static String name = "ten"; public static void f1(){ System.out.println("outer.f1()"); } public void f2(){ System.out.println("inner.f2()"); } //使用static修饰的内部类,即是静态内部类 static class Innerr2{ //静态内部类Innerr可以直接访问外部类Outerr的static属性 //但是无法访问外部类的非静态成员属性 String n = name; //内部类与外部类的方法重名,则就近原则 public static void f1(){ System.out.println("inner.f1()"); } public static void f2(){ System.out.println("inner.f2()"); } } //被private修饰的内部类,其作用域只在Outerr范围内 private static class Innerr{ public static void f1(){ System.out.println("inner.f1()"); } public static void f2(){ System.out.println("inner.f2()"); } } } public class Note2 { public static void main(String[] args) { //可以直接访问静态内部类的方法, 无需创建对象再调用 Outerr.Innerr2.f1(); } }
- 局部内部类(有类名,定义在方法或代码块中)
枚举和注解
- 自定义类实现枚举
-
public class enum02 { public static void main(String[] args) { } } //自定义枚举类 //季节固定只有四个,若增加其他东西,或把名字更改了,则会破坏类的设计思路 class Season2{ //对枚举对象,属性使用final修饰,实现低层优化 //枚举对象使用大写,常量的命名规范 private String name; private String desc; static final Season SPRING = new Season("sp","warm"); static final Season SUMMER = new Season("su","hot"); static final Season AUTUMN = new Season("au","cool"); static final Season WINTER = new Season("wi","cold"); private Season2(String name, String desc) { this.name = name; this.desc = desc; } //不提供setXXX方法 public String getName() { return name; } public String getDesc() { return desc; } }
-
- enum关键字实现枚举
-
enum Season2{ /** 1.使用了enum替代class 2.static Season SPRING = new Season("sp","warm"); 直接写作 SPRING("sp","warm") 3.如果有多个变量,使用,隔开 4.如果使用enum实现枚举,要求将定义常量的对象,写在前面 SPRING("sp","warm"),SUMMER("su","hot"),AUTUMN("au","cool"); */ SPRING("sp","warm"), SUMMER("su","hot"), AUTUMN("au","cool"), //使用无参构造器也可以直接定义 WINTER; private String name; private String desc; private Season2(){ } private Season2(String name, String desc) { this.name = name; this.desc = desc; } public String getName() { return name; } public String getDesc() { return desc; } @Override public String toString() { return "Season2{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } } public class enum02 { public static void main(String[] args) { //枚举类的方法 Season2 s2 = Season2.AUTUMN; //输出枚举对象的name System.out.println(s2.name()); //输出枚举对象的次序,从0开始 System.out.println(s2.ordinal()); Season2.SPRING.toString(); Season2.SPRING.name(); //values()返回Season2[] ,含有定义的所有枚举对象 Season2[] values = Season2.values(); for (Season2 s:values) { System.out.println(s); } //将字符创转换为已有的枚举常量 //根据valueOf()的入参,到Season2的枚举对象中查找,如果找到则返回对象,没有则报错 Season2 ss2 = Season2.valueOf("SPRING"); System.out.println(ss2); //比较两个枚举对象是否相同 System.out.println(s2.compareTo(ss2)); } }
-
- JDK内置的基本注解类型
- 注解
- @override:限定方法是重写父类方法,该注解只能用于方法
- (语法校验)写了注解,则编译器会去检查是否真的重写了父类方法,如果没有重写,则编译错误
- @deprecate:表示某个程序元素已过时(类,方法等)版本升级过渡使用
- 调用变量或者方法时,名字会有中划线
- @suppresswarnings:抑制编译器警告
- @Interface:表示一个注解类,不是注解
- 注解
- 元注解:对注解进行注解