黑马程序员Java基础笔记

类执行顺序

class OrderDemo {
    // 1. 类加载阶段:静态成员(按顺序)
    static int staticVar = 10;
    static {
        System.out.println("静态代码块:staticVar=" + staticVar); // 输出10
        staticVar = 20;
    }

    // 2. 实例化阶段:实例成员(按顺序)
    int instanceVar = 1;
    {
        System.out.println("实例代码块1:instanceVar=" + instanceVar); // 输出1
        instanceVar = 2;
    }
    int instanceVar2 = instanceVar + 1;
    {
        System.out.println("实例代码块2:instanceVar2=" + instanceVar2); // 输出3
    }

    // 3. 构造方法(最后执行)
    public OrderDemo() {
        System.out.println("构造方法:staticVar=" + staticVar + ",instanceVar=" + instanceVar);
        // 输出:staticVar=20(类加载时修改后的值),instanceVar=2(实例代码块修改后的值)
    }

    public static void main(String[] args) {
        System.out.println("首次创建实例:");
        new OrderDemo(); // 触发类加载+首次实例化
        
        System.out.println("\n第二次创建实例:");
        new OrderDemo(); // 仅执行实例化阶段(类加载已完成)
    }
}

继承

方法重写

子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
当通过对象调用方法时,会优先执行该对象实际类型中重写的方法

        Parent p1 = new Parent();
        Parent p2 = new Child(); // 父类引用指向子类实例
        Child c = new Child();

        p1.print(); // 执行Parent的print()
        p2.print(); // 执行Child的print()
        c.print();  // 执行Child的print()

注意: 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。(why?)

构造器

子类所有构造方法的第一行都会默认先调用父类的无参构造方法

多态

1.子类对象继承的父类类型,或者实现的父接口类型。
2.方法的重写【意义体现:不重写,无意义】
3.父类引用指向子类对象【格式体现】
e.g:
Person.java

public class Person {
    String name;
    int age;
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void show(){
        System.out.println("Name: " + name + ", Age: " + age);
    }
}

Man.java

public class Man extends Person {
    String Sex="Male";

    Man(String name, int age) {
        super(name, age);
    }

    @Override
    public void show() {
        System.out.println("I am man");
    }
}

Female.java

public class Female extends  Person {
    String Sex="Female";

    Female(String name, int age) {
        super(name, age);
    }

    @Override
    public void show() {
        System.out.println("I am Female");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Person p1 = new Man("John", 30);
        Person p2 = new Female("lady", 25);
        p1.show();
        p2.show();
    }
}

result:
image
这便是同一行为,具有多个不同表现形式。
调用特性:
Person P=new man("John", 30);

调用成员变量时:编译看左边,运行看左边
P.Sex;
编译看左边:编译的时候看左边父类中有没有这个变量,没有就报编译错误
运行看左边:运行的时候实际获取的就是父类这个变量的值
结论:对于变量来说子类变量父类不能直接访问,可以通过子类的get/set函数来访问或者向下转型将父类引用转为子类引用后,才能访问子类变量
P.show()
调用成员方法时:编译看左边,运行看右边
编译看左边:编译的时候看左边父类中有没有这个方法,没有就报编译错误
运行看右边:运行的时候实际使用的是子类中重写的方法优先使用
结论:编译器检查变量是否可访问时,只依据引用变量的声明类型(即父类类型),而非运行时的实际对象类型(子类)。实际上运行时能准确指向但是编译时搞不清楚。
image

抽象类

注意:抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象类。

接口

在JDK7,包括JDK7之前,接口中的只有包含:抽象方法和常量
接口中的抽象方法默认会自动加上public abstract修饰,在接口中定义的成员变量默认会加上: public static final修饰,程序员无需自己手写!!
如果一个类实现了接口,但是没有重写完全部接口的全部抽象方法,这个类也必须定义成抽象类。
** 如果一个类实现了接口,但是没有重写完全部接口的全部抽象方法,这个类也必须定义成抽象类。**
类与接口是实现关系
接口与接口是继承关系
JDK8以后接口中新增默认方法:public default 返回值类型 方法名(参数列表){}
如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
在接口中,被static修饰的方法,不能被重写,可以直接通过接口名调用
如果一个方法中,当参数为接口时,那么在调用方法时就可传递这个接口的所有实现类对象

理解:接口的本质是一份“契约”,它仅定义“必须做什么”(即方法签名),而不规定“具体怎么做”(即方法实现),核心作用是解耦“行为定义”与“行为实现”,实现多模块间的规范统一 。
解耦:接口隔离了“调用者”和“实现者”。调用者只需知道接口定义的方法,无需关心具体是哪个类实现的(如电脑调用 USB 设备,无需管是U盘还是鼠标,只要符合 USB 接口契约就能用),极大提升了代码的灵活性和可扩展性 。
区别:接口只是一个未实现方法的集合,而抽象类语义上有继承关系
思考:如果一个接口中,有10个抽象方法,但是我在实现类中,只需要用其中一个,该怎么办?
可以在接口跟实现类中间,新建一个中间类(适配器类)
让这个适配器类去实现接口,对接口里面的所有的方法做空重写。
让子类继承这个适配器类,想要用到哪个方法,就重写哪个方法。
因为中间类没有什么实际的意义,所以一般会把中间类定义为抽象的,不让外界创建对象

枚举类

枚举类本质是特殊类,枚举常量(如 ALIPAY)就是这个类的“预定义实例”——在枚举类加载时,JVM 会自动创建所有枚举常量,每个常量都是枚举类的一个对象,且全局唯一(不能通过 new 再创建) 。
image

/* 格式 
enum 枚举名 {
  枚举常量1(值),枚举常量2(值),……
}	*/
enum DayOfWeek {
    MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);
    private int value;
    DayOfWeek(int value) {
        this.value = value;
    }
    public int getValue() {
        return this.value;
    }
}
// 使用
DayOfWeek day = DayOfWeek.MONDAY;
int value = day.getValue();
System.out.println("Today is " + day + ", value is " + value);// 输出Today is MONDAY, value is 1

实现接口的枚举常量

/* 格式 
public interface Operation {
    int apply(int x, int y);
}	*/

public enum BasicOperation implements Operation {
    PLUS("+") {
        public int apply(int x, int y) { return x + y; }
    },
    MINUS("-") {
        public int apply(int x, int y) { return x - y; }
    },
    TIMES("*") {
        public int apply(int x, int y) { return x * y; }
    },
    DIVIDE("/") {
        public int apply(int x, int y) { return x / y; }
    };
    
    private final String symbol;

    BasicOperation(String symbol) {
        this.symbol = symbol;
    }

    @Override public String toString() {
        return symbol;
    }
}

// 使用
int result = BasicOperation.PLUS.apply(1, 2);  // 3

匿名内部类

// 例如
enum Operation {
    PLUS {
        public int apply(int x, int y) {
            return x + y;
        }
    },
    MINUS {
        public int apply(int x, int y) {
            return x - y;
        }
    },
    TIMES {
        public int apply(int x, int y) {
            return x * y;
        }
    },
    DIVIDE {
        public int apply(int x, int y) {
            return x / y;
        }
    };

    public abstract int apply(int x, int y);
}

// 使用
int result = Operation.PLUS.apply(1, 2) // 返回值为3

字符串

image
image
image
image

内部类

匿名内部类

image
{}中才是匿名类,Swim表示实现/继承自它,new表示创建一个实例,()表示调用空参构造器
Swim.java

public abstract class Swim {
    int a,b;
    public Swim(int a,int b){
        this.a=a;
        this.b=b;
    }
    public abstract void swim();
}

Main.java


public class Main {
    public static void main(String[] args) {
        new Swim(1,2){
            @Override
            public void swim() {
                System.out.println(a+b);
            }
        }.swim();
    }
}

拆箱与装箱

//1.利用构造方法获取Integer的对象(JDK5以前的方式)
/*Integer i1 = new Integer(1);
        Integer i2 = new Integer("1");
        System.out.println(i1);
        System.out.println(i2);*/

//2.利用静态方法获取Integer的对象(JDK5以前的方式)
Integer i3 = Integer.valueOf(123);
Integer i4 = Integer.valueOf("123");
Integer i5 = Integer.valueOf("123", 8);

System.out.println(i3);
System.out.println(i4);
System.out.println(i5);

//3.这两种方式获取对象的区别(掌握)
//底层原理:
//因为在实际开发中,-128~127之间的数据,用的比较多。
//如果每次使用都是new对象,那么太浪费内存了
//所以,提前把这个范围之内的每一个数据都创建好对象
//如果要用到了不会创建新的,而是返回已经创建好的对象。
Integer i6 = Integer.valueOf(127);
Integer i7 = Integer.valueOf(127);
System.out.println(i6 == i7);//true

Integer i8 = Integer.valueOf(128);
Integer i9 = Integer.valueOf(128);
System.out.println(i8 == i9);//false

//因为看到了new关键字,在Java中,每一次new都是创建了一个新的对象
//所以下面的两个对象都是new出来,地址值不一样。
/*Integer i10 = new Integer(127);
        Integer i11 = new Integer(127);
        System.out.println(i10 == i11);

        Integer i12 = new Integer(128);
        Integer i13 = new Integer(128);
        System.out.println(i12 == i13);*/

克隆

浅克隆:

含义:浅克隆是指在克隆对象时,只复制对象本身和其中的基本类型数据,而不复制对象中引用类型的数据,此时复制出来的对象与原对象共享引用类型数据所在的地址。
特点:当原对象中引用类型数据发生改变时,复制出来的对象也会发生变化。

深克隆:

含义:在克隆对象时,不仅复制对象本身和其中的基本类型数据,还要对对象中的引用类型数据进行递归复制,以确保复制出来的对象与原对象的所有数据完全独立,互不影响
特点:可以保证克隆出来的对象与原对象完全独立,互不影响
注意:深克隆会比浅克隆更加耗费时间和资源,但可以保证克隆出来的对象与原对象完全独立,互不影响。而浅克隆虽然速度快,但是容易出现数据共享的问题,需要特别注意
不会自己写,使用别人的工具类

import com.google.gson.Gson;

public class Test {
   public static void main(String[] args) {
       Person p1=new Person("Alice", 30);
       System.out.println(p1);
       Gson gson=new Gson();
       //将对象转换为JSON字符串
       String json=gson.toJson(p1);
       System.out.println(json);
       //将JSON字符串转换为对象
       Person p3=gson.fromJson(json,Person.class);
       p3.setName("bob");
       System.out.println(p3);
   }
}

正则表达式

image

public class Test {
    public static void main(String[] args) {
        String str="sb  shisohfs ss";
        //获得正则表达式对象
        Pattern p= Pattern.compile("sb");
        //获取文本匹配器对象
        Matcher m = p.matcher(str);
        //find()如果有返回true且底层记录子串起始索引和结束索引+1
         while(m.find()){
             //group()返回字串,调用的是subString()
                System.out.println(m.group());
         }
    }
}
//?表示前面的Java,=表示连接后面的8或11或17但是不包含在结果中,(?i)表示后面字段大小写都匹配
        String reg="((?i)Java)(?=8|11|17)";
        String reg="((?i)Java)(?:8|11|17)"; //:表示留下在结果中
        String reg="((?i)Java)(?!8|11|17)";//!表示不要这样的串

贪婪爬取:ab+,尽可能多的b
非贪婪爬取:ab+?,尽可能少的b
image
image
正则内部:\组号
正则外部:$组号
image
(?:)(?=)(?!)是非捕获分组不占用组号

Lambda

image
image

image

方法引用

简化了Lambda

静态方法引用

image

实例方法引用

image

特定类型方法引用

image

构造器引用

image

泛型

image

//泛型类
public class Test <E> {
    public Test() {    }

    public void add(E e){
        System.out.println(e.toString());
    }
    //泛型方法
    public static <T> T show(T t){
        return (T) t.toString();
    }

    public static void main(String[] args) {
        Test<Person> t= new Test<>();
        t.add(new Person());
        System.out.println(Test.show("adidas"));
    }
}

通配符

image
泛型只支持引用类型,因为泛型会被擦除,它只工作在编译阶段,编译后它就没有了,所有类型会变为Object,而Object接不了基本类型。

集合

image

Collection

image

遍历方式

迭代器

image
image

foreach

image

Lambda

image

并发修改异常

就是一边遍历一边增删
image
foreach与Lambda解决不了并发修改异常问题,只适合做遍历。

Set

image
image
image
image
image
image
自定义排序规则:
1.实现Comparable接口,重写comparaTo方法
2.TreeSet自带比较器对象,指定规则。

自定义对象去重

image

Map

image
键不重复,同键的值后面覆盖前面的

遍历

1.根据键找值

HashMap<String, Integer> m = new HashMap<String,Integer >();
Set<String> keys=m.keySet();
for(String key:keys){
  m.get(key);
}

2.键值对
image
Map.Entry是接口不是对象,实现类是其内部的Node (key,value)

3.Lambda
image

image

image
image

Stream流

image
image
image
image
of(T ... values)中...表示可变参数
image
image
Optional是一个含量为1的容器,可以存NULL
image

File

image
image
image
image
image
image

编码

image
image

IO流

I还是O是相对于内存来说的
image

image
image
image
image
image
image

image
文件字节输入/输出流不一定比缓冲流慢,速度根据接数据的字节数组大小成正比,超过32KB后速度增长不明显
image
按照字符去读不会出现中文编码截断问题。

image
image

资源释放

image
image

缓冲流

image
image
image
image
image
image
image
image
image

打印流

image
image
包的BufferWriter
image
追加包低级的流
image

特殊流

image

image

IO框架(重要)

image
image

多线程

创建

image

image
image

image
image

image
image

image
image

常用方法

image

同步代码

image

image
image

线程池(复用线程)

不会来一个任务就创建一个线程,导致开销巨大
image
image
image
image
image
线程工厂是new出线程,然后完成任务

image
image
image
image

多进程

网络编程

image

UDP

image

public class Clients {
    public static void main(String[] args) throws Exception {
        System.out.println("UDP客户端启动...");
        // 创建发送对象
        DatagramSocket clientSocket=new DatagramSocket();//随机端口
        //构造消息
        byte[] massage="再不学习就要G了".getBytes();
        //创建数据包
        DatagramPacket packet=new DatagramPacket(massage,massage.length, InetAddress.getLocalHost(),8080);
        //发送数据包
        clientSocket.send(packet);

    }



}
public class Service {
    public static void main(String[] args) throws Exception {
        System.out.println("UDP客户端启动...");
        // 创建接受对象
        DatagramSocket clientSocket=new DatagramSocket(8080);
        //构造接受载体
        byte[] massage=new byte[1024*64];//UDP数据包最大64K
        //创建接受数据包
        DatagramPacket packet=new DatagramPacket(massage,massage.length);
        //发接受数据包
        clientSocket.receive(packet);
        System.out.println(new String(massage,0,packet.getLength()));
        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(packet.getPort());

    }
}

TCP

image
image

image
image
image

posted @ 2025-10-20 20:12  under_world  阅读(14)  评论(0)    收藏  举报