JavaSE复习笔记

JavaSE

此笔记为作者复习所写,未经允许不得转发,可供读者参考

*基本知识点

对象赋值

​ Person p1 = p;

​ 含义:把p的地址传给p1,导致p1和p指向堆空间中的同一个对象实体(若Person对象不重写toString方法,那么输出对象时即为地址)

String
判断字符串是否相等

​ (1) Objects.equals(String s1, String s2);

​ (2) s1.equals(b);

String方法

​ String trim() 返回str副本,即忽略前导空白和尾部空白

​ int compareTo() 返回第一个不同字母的ASCII之差

​ boolean startsWith(String str) 判断str是否以str开始

​ boolean endsWith(String str) 判断str是否以str结束

​ boolean matches(regex) 判断是否匹配(注:regex是正则表达式 Regular Expression)

String 与 char[] 的转换

String -> char[] str.toCharArray()

char[] -> String (1) Arrays.toString(char[]) [a, b, c]

​ (2) String str = new String(char[]) abc

String 与 bytes[] 的转换

编码:String -> bytes[] str.getBytes[]

解码:bytes[] -> String String str = new String(bytes[])

String特性

​ (1) final类,不可变的字符序列

​ (2) 实现了Serializable接口,支持序列化

​ (3) 实现了Comparable接口,可比较大小

​ (4) 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串声明在字符串常量池中,字符串常量池中不会存储相同内容的字符串,当对字符串重新赋值时,需要重新指定内存区域赋值,不能在原有的value上赋值(意思是重新赋值的字符串的地址会改变)

String s1 = "abc";
String s2 = "def";
String s3 = s1 + s2;
String s4 = "abcdef";
String s5 = "abc" + "def";
String s6 = s3.intern();//返回值s6在常量池中
System.out.println(s3 == s4)//false
System.out.println(s4 == s5)//true
System.out.println(s4 == s6)//true
可变形参个数的方法

​ ① 格式:数据类型 . . . 变量名 (eg: String . . . str)

​ ② 当同时存在String str和String . . . str时,构成重载, 且当传入一个String参数时,优先进入String str

Lambda表达式和方法引用

Lambda格式:(形参列表) -> Lambda体

->:Lambda操作符

Lambda体:重写的抽象方法的方法体

当方法体中只有一条语句时,可以省略{}和return

使用条件:必须是函数式接口(@FunctionalInterface),即接口中只声明了一个抽象方法

Lambda的本质:作为接口的实例(即对象)

方法引用格式:类(or对象)::方法名

//原始
Comparator<Integer> comparator = new Comparator<Integer>() {
	@Override
	public int compare(Integer o1, Integer o2) {
		return o1.compareTo(o2);
		}
	};

//Lambda
Comparator<Integer> comparator = (o1, o2) -> o1.compareTo(o2);//因为只有一条语句,故省略了{},return

//方法引用
Comparator<Integer> comparator = Integer::compareTo;
//方法引用用于遍历(ps:比较有逼格)
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.forEach(System.out::println);	//拿来炫

*关键字

instanceof

​ ① (boolean) a instanceof A : 判断a 是否是A 的实例

​ ② 较高级的数据类型 -> 较低级的数据类型 (强制类型转化)

​ 较低级的数据类型 -> 较高级的数据类型 (自动类型提升)

​ ③ 父类 -> 子类 (向下转型,同强制类型转化)

​ 子类 -> 父类 (向上转型,多态)

为了避免ClassCastException异常,向下转型前需要用instanceof判断

​ ④ 如果 a instanceof A == true && a instanceof B == true

​ 那么 A 是 B 的子类

static

​ 实例变量(非静态):创建的类的多个对象,每个对象独立拥有一套非静态属性,彼此互不干扰

​ -静态变量:多个对象共享同一个静态变量,当修改某个对象的静态变量时,其他对象的此静态变量也会被修改

① static修饰属性(静态属性):

​ (1) 静态属性随着类的加载而加载,可用"类.静态变量"来调用

​ (2) 静态变量的加载早于对象

​ (3) 静态变量存在方法区的静态域中

② static修饰方法(静态方法):

​ (1) 通过"类.静态方法"来调用

​ (2) 静态方法中,只能调用静态属性或方法;而非静态方法既能调用非静态,也能调用静态

经验之谈:(1) 若属性可被多个对象共享,不会因为对象的不同而改变,那么该属性可设置为static

​ (2) 操作静态属性的方法,及工具类的方法,声明为static

final

​ ① 修饰类:此类不可被继承(没有子类)(例如:String,System,StringBuffer)

​ ② 修饰方法:此方法不可被重写 (例如:Object类中的getClass())

​ ③ 修饰变量:常量

​ ④ static final 修饰变量:全局常量

多线程

概念

​ 程序(program):一段静态的代码

​ 进程(process):正在运行的一个程序

​ 线程(thread):进程可细化为线程,是程序内部的执行路径

​ 并行:多个CPU同时执行多个任务

​ 并发:一个CPU(采用时间片),“同时”执行多个任务

​ 一个java应用程序,至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程

多线程的创建
法1:继承Thread类

步骤:继承Thread类 -> 重写run() -> 创建子类对象 -> 调用start()

法2:实现Runnable接口

步骤:创建一个类实现Runnable接口 -> 创建对象 -> 将此对象作为参数传递给Thread类的构造器,创建Thread类对象 -> Thread类对象调用start()

法3:实现Callable接口
public class ThreadNew implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
            System.out.println(i);
        }
        return sum;
    }
}
@Test
public void test() throws ExecutionException, InterruptedException {
    ThreadNew threadNew = new ThreadNew();
    FutureTask futureTask = new FutureTask(threadNew);
    new Thread(futureTask).start();
    System.out.println(futureTask.get());
}
线程的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FLVgngg-1656840376560)(C:\Users\一熹\AppData\Roaming\Typora\typora-user-images\image-20220702190859361.png)]

线程同步(线程安全问题)
法1:synchronized
synchronized(同步监视器){
	//需要被同步的代码
    //即:操作共享数据的代码
    //同步监视器:俗称锁,要求多个线程共用一把锁
}
法2:同步方法

在操作共享数据代码的方法上标注synchronized

法3:Lock
private ReentrantLock lock = new ReentrantLocak();
lock.lock();
//需要被同步的代码
lock.unlock();//与synchronized的区别:需要手动解锁
常用方法

​ start() 启动当前线程,调用当前线程的run()

​ run() 重写run(), 将需要进行的操作声明在内

​ currentThread() 返回当前的线程

​ getName() 返回线程的名字

​ setName() 设置线程的名字

​ yield() 释放当前CPU的执行权

​ join() 在a中调用b的join,a进入阻塞状态,直到b执行完以后,a才结束阻塞状态

​ sleep(long millionTime) 让当前线程睡眠指定时间

​ isAlive() 判断线程是否存活

线程的通信

​ wait() 执行后,当前线程阻塞,并释放同步监视器

​ notify() 执行后,唤醒被wait()的一个线程

​ notifyAll() 执行后,唤醒所有被wait()的线程

​ 使用前提:必须使用在synchronized修饰的同步代码块或同步方法中

线程的调度

​ ① 调度策略:时间片(同优先级)

​ 抢占式(不同优先级:高优先级的线程抢占CPU)

​ ② 优先级:Thread.MIN_PRIORITY = 1;Thread.NORM_PRIORITY = 5;Thread.MAX_PRIORITY = 10

​ ③ 方法:setPriority() getPriority()

bug

​ ① junit 对 多线程进行单元测试,大概率会运行不完所有线程

原因:junit在运行时,在主线程结束后就关闭了进程(System.exit()方法,将JVM关闭,其他线程直接挂哩),不会等待各个线程运行结束

解决方法:Thread.sleep(long millionTime)让main线程阻塞一会儿,等着其他线程结束

*设计模式

单例设计模式
饿汉式

​ ① 私有化构造器

​ ② 内部创建对象

​ ③ 提供公共静态方法返回对象

public class Bank{
    private Bank(){}
    private static Bank instance = new Bank();
    public static Bank getInstance(){
        reuturn instance;
    }
}

public static void main(String[] args){
    Bank bank = Bank.getInstance;
}
##### 懒汉式
public class Bank{
    private Bank(){}
    private static Bank instance = null;
    public static Bank getInstance(){
        if(instance == null)
            instance = new Bank();
        return instance;
    }
}
线程安全的懒汉式
public class Bank {
    private Bank() {}
    private static Bank instance = null;
    public static Bank getInstance() {
        if (instance == null) {
            synchronized (Bank.class) {
                if (instance == null) {
                    instance = new Bank();
                }
            }
        }
        return instance;
    }
}

优缺点比较:

饿汉式:优点:线程安全。缺点:对象加载时间过长

懒汉式:优点:延迟对象的创建。缺点:线程不安全(需要同步)

模板方法设计模式

​ 在实现一个算法时,整体步骤固定通用,且已经在父类中写好了。但某些部分易变,易变部分可以抽象出来,供不同子类实现

//计算某段代码执行所花费的时间
public void spendTime(){
    long start = System.currentTimeMillis();
    code();//不确定、易变的部分
    long end = System.currentTimeMillis();
    System.out.println("花费的时间为:" + (end - start));
}

代理模式

​ 为其他对象提供一种代理以控制对这个对象的访问

工厂模式

​ 实现创建者与调用者的分离,即将创建对象的具体过程隐蔽起来,达到提高灵活性的目的

工具类
Objects类

​ ① equals()

​ equals() 与 == 的区别

​ ==:(1) 用于基本数据类型(boolean除外):比较数据

​ (2) 用于引用数据类型(类,数组,接口):比较地址值

​ equals():虽然String是引用数据类型,但是像String、Date、File、包装类等都重写了equals()方法,因此比较数据,而非地址

//重写equals() 简略版

public boolean equals(Object obj){
    if(this == obj)
		return true;//比较地址
    if(obj instanceof User){
        User user = (User)obj;
        return this.age == user.getAge() && this.name.equals(user.getName());
    }
    return false;
}

​ ② toString():(1) 当我们输出一个对象时,实际上是调用的这个对象的toString()方法

​ toString()源码:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

​ ③ 像String、Date、File、包装类等都重写了toString()方法,调用时返回实体内容信息

Arrays类

​ (1) boolean equals (int[] a, int[] b); 判断a, b是否相等

​ (2) String toString(int[] a); 输出[, , ,]

​ (3) void fill (int[] a, int value); 将value替换a中的所有值

​ (4) void sort(int[] a); 排序

​ (5) int binarySearch(int[] a, int value); 二分法查找递增数组中的value,并返回索引

Collections类

​ (1) shuffle(List) 随机

​ (2) sort(List) / sort(List, Comparator) 排序

​ (3) int frequency(List, Object) 返回obj出现的次数

​ (4) copy(dest, src)

​ (5) synchronizedXXX() 解决线程安全问题

包装类

​ ① 基本数据类型 byte/short/int/long/float/double/boolean/char

​ 包装类Byte/Short/Integer/Long/Float/Double:父类是Number

​ Boolean/Character

​ ② 装箱: 基本类 -> 包装类 : 调用包装类的构造器: Integer integer = new Integer(1);

​ 拆箱: 包装类 -> 基本 : 调用包装类的xxxValue(); int i = integer.intValue();

​ ③ 自动装箱: Integer integer = 1;

​ 自动拆箱: int i = integer;

​ ④ 基本 -> String:(1) String str1 = num1 + “”;

​ (2) String -> 基本:String str1 = String.valueOf(num1);

​ String -> 基本:int num1 = Integer.parseInt(str);

System类

(1)currentTimeMillis 时间戳

(2)void exit(int status) 0正常退出,非0异常退出

(3)void gc() 垃圾回收

(4)String getProperty(String key) key:java.home/java.version/os.name/os.version/user.name/user.home/user.dir

Collection类

-Collection 单列集合,用来存储一个一个对象

​ -List 存储有序,可重复数据 (动态数组)

​ -Set 存储无序,不可重复数据 (集合)

-Map 双列集合,存储一对一对(key->value键值对)的数据(函数映射,可多对一,不可一对多)

Colletion
//方法引用
collection.forEach(System.out::println);	//遍历Collection元素
Iterator

集合遍历

List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
//hasNext()	判断是否还有下一个元素
//next()	遍历一个元素(指针下移,将下移后集合位置上的元素返回)
//remove()	在遍历时可以移除某个元素
//注意:集合对象每次调用iterator()方法都会得到一个全新的迭代器对象,默认游标在集合的第一个元素之前(-1)
*List
###### ArrayList
//建议使用带参构造器
ArrayList list = new ArrayList(int capacity)
    
    
/*
jdk7:	1.底层创建了长度为10的Object[]
   		2.如果容量不够,扩容成1.5倍
   		
   		
jdk8:	1.Object[]初始化无长度
		2.第一次调用add(),底层才创建长度10的数组
		3.后续与jdk7相同
		
小结:jdk7类似于单例模式的饿汉,jdk8类似于懒汉,延迟了数组的创建,节省了内存
*/
LinkerList

​ 内部声明了Node类型的first,last属性,默认为null,Node的定义体现了双向链表

Vector

​ 底层创建长度为10的数组,扩容为2倍

*Set
HashSet

添加元素的过程:

1.计算对象的hash值,通过一定的算法将哈希值转成index

2.在此索引处存入该对象

3.若两个对象索引相同:
3.1先比较哈希值:若不同,则将2个对象以链表的形式存储

​ 3.2 若相同:比较equals(),若返回值为true,则两个对象真的相等

​ 返回值为false,再以链表形式存储

小结:HashSet底层:数组+链表

​ 相同的对象,必须具有相同的hashcode()

LinkedHashSet

​ 在添加数据的同时,每个数据还维护2个引用,记录此数据的前一个和后一个(类似于链表)

优点:频繁遍历操作,效率优于HashSet

TreeSet

​ 向TreeSet中添加的数据,必须是相同类的对象

​ TreeSet依靠compareTo比较是否相等,而不是equals()

​ 可用自然排序(comparable),定值排序(comparator)

*Map
HashMap

​ key:无序、不可重复,用Set存储 -> key所在类重写equals(),hashcode()

​ value:无序、可重复,用Collection存储 -> value所在类重写equals()

​ 一个键值对构成一个Entry对象

Map中的Entry:无序不可重复,用Set存储

//底层原理
/*
	jdk7:实例化时底层创建一个16的数组Entry[] table
	扩容为2倍(当超出临界值12,且存放的位置非空)
	(底层结构:数组+链表)
	
	jdk8:实例化时长度为0
	首次调用put()时,才创建数组
	当数组的索引的链表长度>8且数组长度>64时,链表改为红黑树,否则扩容
	(底层结构:数组+链表+红黑树)
*/
LinkedHashMap

​ 同LinkedHashSet

TreeMap

​ 只能按照key排序

枚举类
public enum Season {
    SPRING("春天"),
    SUMMER("夏天"),
    AUTUMN("秋天"),
    WINTER("冬天");

    private final String seasonName;

    Season(String seasonName) {
        this.seasonName = seasonName;
    }

    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                '}';
    }

}

常用方法:

(1)toString 打印枚举名称

(2)values 获取所有枚举类名称

(3)valueOf(String str) 将字符串转化成对应的枚举类对象

Java比较器

​ 给对象排序,使用Comparable或Comparator接口。像String、包装类等实现了Comparable接口,重写了CompareTo方法

自然排序

对自定义的类来说,如果需要排序,就要实现Comparable接口,重写CompareTo方法

//先按价格排序,再按姓名排序
@Override
    public int compareTo(Object o) {
        if (o instanceof Goods) {
            Goods goods = (Goods) o;
            if (this.getPrice() > goods.getPrice()) {
                return 1;
            } else if (this.getPrice() < goods.getPrice()) {
                return -1;
            } else {
                return this.getName().compareTo(goods.getName());//String类已经重写了compareTo()
            }
        } else {
            return 0;
        }
    }
定制排序Comparator
 Arrays.sort(arr, new Comparator<Goods>() {		//此处可替换为lambda表达式
            @Override
            public int compare(Goods o1, Goods o2) {
                if(o1.getPrice() > o2.getPrice()){
                    return 1;
                }else if(o1.getPrice() < o2.getPrice()){
                    return -1;
                }else {
                    return o1.getName().compareTo(o2.getName());
                }
            }
        });

IO流

File类

File类一个对象,代表一个文件或文件目录(dir)

creatNewFile 创建文件

mkdir/mkdirs 创建文件夹

delete file/dir 删除

原理及分类

输入:外部数据(磁盘) -> 内存(程序)

输出:程序(内存) -> 外部数据

分类

字节流(8bit) 字符流(16bit)

输入流 输出流

节点流 处理流

注意:文本文件:txt、java、c、cpp 使用字符流

非文本文件:jpg、mp3、mp4、avi、doc、ppt 使用字节流

抽象基类

字节输入流:InputStream

字节输出流:OutputStream

字符输入流:Reader

字符输出流:Writer

流的体系结构
节点流(文件流)

FileInputStream、FileOutputStream、FileReader、FileWriter

缓冲流

提高流的读取、写入速度

Buffered~

flush刷新缓冲区

转换流

InputStreamReader 字节输入流 -> 字符输入流 (解码)

OutputStreamWriter 字符输出流 -> 字节输出流 (编码)

字符集

ASCII、GBK、Unicode、UTF-8、ANSI

标准输入输出流

System.in 标准输入流

System.out 标准输出流

打印流

PrintStream 输出字节流

PrintWriter 输出字符流

数据流

DataInputStream

DataOutputStream

对象流

ObjectOutputStream

ObjectInputStream

public static final long serialVersionUID 序列化版本号

随机存储文件流

RandomAccessFile

网络编程

基础知识

IP(Internet Protocol):InetAddress类:标识互联网上的计算机。分类:ipv4,ipv6,局域网,万维网

域名:www.baidu.com

DNS:域名解析服务器

本地回路地址:127.0.0.1 对应:localhost(域名)

端口号:标识正在计算机上运行的程序,不同进程有不同的端口号(1~65535)

网络协议

TCP:使用前建立连接,形成通道:三次握手,四次挥手;客户端,服务端;进行大数据量传输;效率低(类似于打电话)

UDP:不需要建立连接,将数据、源、目的封装成数据包;无需确认;可广播发送;结束时无需释放资源,开销小,速度快(类似于发短信)

URL网络编程

url:统一资源定位符,表示Internet上某一资源的地址

构成:<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

eg:http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123

*反射

反射被视为动态语言的关键,允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

类的加载过程

​ 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class后缀),接着我们使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程称为类的加载。加载到内存中的类,称为运行时类,此类就作为Class的一个实例

​ 即Class的一个实例就对应一个运行时类

​ 加载到内存中的运行时类,会缓存一定的时间,可通过以下方式来获取(非new)

获取运行时类
		//1.调用类.class
        Class clazz1 = Person.class;
        
        //2.通过运行时类的对象
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        
        //***3.通过Class的forName
        Class clazz3 = Class.forName("Person");//全类名

		//4.类的加载器
		ClassLoader cl = Person.class.getClassLoader();
        Class clazz4 = cl.loadClass("Person");//全类名
创建运行时类的对象

newInstance() 创建对应运行时对象,内部调用了运行时类的空参构造器(非private)

获取运行时类的属性结构及其内部结构
clazz调用

getDeclaredFields() 获取当前类所有属性

getTypeName() 获取类名

getDeclaredConstructors 获取当前类所有构造器

getDeclaredMethods 获取当前类所有方法

method调用

getAnnotations/getModifiers/getReturnType/getName/getParameterTypes/getExceptionTypes

获取父类以及带泛型父类

getSuperClass 获取父类

getGenericSuperClass 获取带泛型父类

获取接口

getInterfaces/getPackage/getAnnotations

调用运行时类中指定结构
属性
		Class clazz = Class.forName("Person");//获取Person类实例
        Person p = (Person) clazz.newInstance();//创建对象
        Field name = clazz.getDeclaredField("name");//获取属性对象(属性名)
        Field age = clazz.getDeclaredField("age");
        name.setAccessible(true);//保证当前属性可访问
        age.setAccessible(true);
        name.set(p,"Origami");//设置属性值
        age.set(p,19);
        String n = (String) name.get(p);
        Integer a = (Integer) age.get(p);
        System.out.println("name = " + n + ", age = " + a);
方法
public String showName(String habit){
        System.out.println("name = " + name + ", and my habit is " + habit);
        return habit;
}
//	---------------------------------------------------------------------
		Class clazz = Class.forName("Person");//获取Person类实例
        Person p = (Person) clazz.newInstance();//创建类对象
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p,"Origami");
        Method showName = clazz.getDeclaredMethod("showName",String.class);//获取方法对象(方法名,形参列表的类型)
        showName.setAccessible(true);//保证可以访问
        Object invoke = showName.invoke(p,"coding");//调用方法(调用者,实参)
		//invoke 的返回值,即为方法的返回值
        System.out.println(invoke);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马javase笔记是一份比较详细的Java基础学习笔记,适合初学者或者复习巩固Java知识的人使用。这份笔记是作者在两年时间内多次复习Java后总结出来的,其中包括了不同老师的举例和作者自己的感悟。这份笔记的内容力求通俗易懂,同时也包括了方法区和JVM(Java Virtual Machine)的介绍。方法区是字节码文件加载时进入内存的区域,字节码文件由Java源文件编译而成。JVM是Java虚拟机,用来运行Java字节码文件,它的关键作用是屏蔽了不同操作系统之间的差异,使得相同的Java程序可以在不同的操作系统上得到相同的结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java基础笔记MarkDown版4万字肝吐血](https://download.csdn.net/download/qq_33865785/88275967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【学习笔记/自用】黑马程序员javase2023版-基础](https://blog.csdn.net/qq_41014040/article/details/129164451)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值