Java总结

文章目录


前言

总结一些Java学习过程中的笔记


Java基础

一、Java版本

JavaSE:标准版
JavaEE:企业级开发


二、JDK JRE JVM

JDK(java开发者工具):Java Development Kit
JRE(java运行环境):Java Runtime Environment
JVM(java虚拟机):Java Virtual Machine
JDK包含JRE、JVM,JRE包含JVM


三、java文件的编译过程

Java源文件(.java),通过javac(Java编译器)编译成字节码文件(.class),放到虚拟机中的类加载器里加载对应的类,再用字节码校验器检查代码规则,最后通过解释器解释给操作系统。
在这里插入图片描述


四、注释

public class Hello {
    public static void main(String[] args) {
        //这是单行注释
        /*
        这是多行注释
        快捷键:/* + Enter
         */
        /**
         * 这是文档注释
         * 快捷键:/** + Enter
         * @Deprecated HelloWorld
         * @Author  
         */
        System.out.println("hello");
    }
}

五、数据类型

1.基本数据类型(8个)

1)数值型
整数类型:byte、short、int、long
定义long类型一般要在后面加L

long num = 30L;

浮点类型:float、double
定义float类型一般要在后面加F(必须加)

float num = 50.1F;

(为什么需要加L/F点此跳转)
2)字符型:char
3)布尔型:boolean
在这里插入图片描述

1)基本数据类型拓展

1、整数

public class Hello {
    public static void main(String[] args) {
       //整数拓展   二进制0b   十进制     八进制0    十六进制0x
       int i = 10;
       int i2 = 0b10;
       int i3 = 0x10;
       int i4 = 010;

       System.out.println(i);
       System.out.println(i2);
       System.out.println(i3);
       System.out.println(i4);
    }
}

在这里插入图片描述
2、类型转换

由低到高(小数的优先级大于整数)
byte,short,char->int->long->float->double

高转低需要强制类型转换

转化的时候要注意可能存在内存溢出,或者精度问题
在这里插入图片描述
在这里插入图片描述

2)String

String类代表字符串。效果上相当于字符数组(char[]),底层原理是字节数组(byte[])_对应ASCII码
在这里插入图片描述

3)StringBuilder

1、前序

在这里插入图片描述
如上图所示,在进行字符串拼接时,每次拼接都会构建一个新的String对象,耗时且浪费堆内存。
String s = “hello”; //在常量池中创建了地址为001的常量hello,s指向地址001
s += “world”; //s = s + "world"; 先在常量池中创建了地址为002的常量world。s+“world”,在常量池中创建了地址为003的"helloworld",s再指向地址003
此时,用StringBuilder解决这个问题

2、概述
StringBuilder是一个可变(指的是StringBuilder对象中的内容可变)的字符串类,可以当做是一个容器。
在这里插入图片描述
在这里插入图片描述
append()方法解决了上述问题,因为append()返回的是对象本身,无需另外开辟地址空间,可以将append()理解成拼接用的方法
在这里插入图片描述

3、与String的区别
String的内容不可变;StringBuilder可变


2.引用数据类型

类、接口、数组


六、运算符

1.逻辑运算符

&&(短路与):两个变量都为真,结果才为true。若左边的为false,直接返回false,右边的条件不执行。
||:两个变量有一个为真,结果就为true。

2.位运算

A = 0011 1100
B = 0000 1101

A&B = 0000 1100 均为1才为1,其余为0
A|B = 0011 1101 有一个为1,就为1
A^B = 0011 0001 异或,相同为0,不同为1
~B = 1111 0010 取反

“<<n” 左移,将数字转换为2进制,左移n位,移除的空位补0
“>>n” 右移,将数字转换为2进制,右移n位,移除的空位正数补0,负数补1
“>>>n” 无符号右移,将数字转换为2进制,右移n位,忽略符号位,无论正负均补0

4<<1
0000 0000 0000 0000 0000 0000 0000 0100 -> 0000 1000 = 8
4>>1
0000 0000 0000 0000 0000 0000 0000 0100 -> 0000 0010 = 2
-4>>1
-4的源码1000 0000 0000 0000 0000 0000 0000 0100,补码1111 1111 1111 1111 1111 1111 1111 1100,右移一位后1111 1111 1111 1111 1111 1111 1111 1110,再减1得1111 1111 1111 1111 1111 1111 1111 1101,最后转成源码1000 0000 0000 0000 0000 0000 0000 0010=-2
-4>>>1
-4的源码1000 0000 0000 0000 0000 0000 0000 0100,补码1111 1111 1111 1111 1111 1111 1111 1100,右移一位后变成正数(源码和补码一样)0111 1111 1111 1111 1111 1111 1111 1110=2147483646

字符串连接符

public class Hello {
   public static void main(String[] args) {
       int a = 30;
       int b = 40;

      System.out.println("" + a + b);	//3040,
      System.out.println(a + b + "");	//70
   }
}

七、方法

1.形参和实参;return的两个作用

public class Hello {
    public static void main(String[] args) {
        int max = max(10,20);   //此处为实参
        System.out.println(max);
    }

    public static int max(int a, int b) {   //a和b为形参
        int result = 0;

        if (a == b) {
            //终止方法
            return 0;
        }

        if (a < b) {
            result = b;
        } else {
            result = a;
        }

        //返回值
        return result;
    }
}

值传递和应用传递?

2.方法的重载

重载:

一个类中,有相同的方法名,但形参不同的方法。

规则:

1、方法名必须相同
2、参数类型不同、参数个数不同、参数排列顺序不同

3.动态参数(可变参数)

在定义一个方法的时候,我们也不确定需要定义多少个形参,这个时候可以用到动态参数。

方法声明中,在指定参数类型后加一个省略号...

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.alterParameter(2,3,4,5);
    }

    //动态参数
    public void alterParameter(int... i) {
        System.out.println(i[2]);
    }
}

一个方法中只能指定一个动态参数,而且必须是方法的最后一个参数
在这里插入图片描述
在这里插入图片描述

举例:
在这里插入图片描述


八、数组

1.初始化

public class Test {
    public static void main(String[] args) {
        //1、静态初始化
        int[] a = {1,2,3,4,5};
        
        //2、动态初始化:包含默认初始化
        int[] b = new int[5];
        b[0] = 10;
        
        //3、默认初始化
        //数组是引用类型,其中的元素相当于类的实例变量,因此数组被分配空间好,其中的每个元素也会被隐式初始化
    }
}

2.四个基本特点

1、长度是确定的。一旦被创建,大小不可更改。
2、元素类型必须相同。
3、数组元素可以是任何数据类型。
4、数组变量属于引用类型,数组也是一个对象,数组中每一个元素都相当于该对象的成员变量。因为Java中对象(new出来的)都是在堆中,所以数组是保存在堆中的

3.Arrays类

可以自己看下源码
Java8 中文版API
.asList()与ArrayList的区别

  • asList()的源码
    在这里插入图片描述
    在这里插入图片描述
    虽然.asList()方法将数组转化成集合,但可以看出这个ArrayList类是Arrays类自己定义的一个私有静态内部类

4.将数组转化为集合的三种方式

1)通过Arrays.asList()方法

支持查询

public void test1(){
    String[] arr = {"0","1","2"};
    List<String> list = Arrays.asList(arr);
    // 对转换后的list插入一条数据
    list.add("aa");
    System.out.println(list);
}
2)通过ArrayList的构造器

支持增删改查

public void test2(){
    String[] arr = {"0","1","2"};
    ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));
    // 对转换后的list插入一条数据
    list.add("aa");
    System.out.println(list);
}

3)通过集合工具类Collections.addAll()

支持增删改查,如果数据量大,效率高

public void test3(){
    String[] arr = {"0","1","2"};
    ArrayList<String> list = new ArrayList<>(arr.length);
    Collections.addAll(list, arr);
    // 对转换后的list插入一条数据
    list.add("aa");
    System.out.println(list);
}


面向对象

一、面向过程/对象思想

面向过程思想:步骤化,线性的思维
面向对象思想:模块化,分类的思维


二、new

实例化类,返回一个对象。类是抽象的,对象是类的具体实例。

创建对象时,除了分配内存空间之外,还会给创建好的对象进行默认的初始化,以及对类中构造器的调用


三、构造方法(构造器)

1.定义及特点

创建类的时候,即使这个类中什么都没有,也自动存在一个方法,这个方法就是构造器。

1、构造器必须与类名相同
2、没有返回类型

使用new关键字,本质是在调用构造器,也可以说构造器用来初始化值

2.无参构造和有参构造

1)无参构造是自动生成的,是隐式的。
2)有参构造是我们自己创建的,一旦定义了有参构造,无参构造必须存在且为显式定义。


四、创建对象内存分析

以下是个人理解。专业的分析可以看下面推荐的一个视频。
狂神说Java:创建对象内存分析

1.内存中的三个组件:栈、堆、方法区

1)栈和堆是独立存在的,方法区在堆中。
2)栈中存放项目的main()、引用数据类型的变量
3)堆中存放类实例化后的对象
4)方法区中存放类信息、常量池(存放常量)、成员方法、静态方法区(由static关键字修饰的方法和变量)

2.运行过程

  • 程序开始运行,加载static类的一些信息(方法、常量),存放在方法区中;
  • 走到基础类中的main(),入
  • 进入main(),走到XXX xxx = new XXX(),此时要加载XXX类才能实例化构造器XXX(),所以方法区中又存入了XXX类的一些信息(方法、常量);
  • new XXX()即XXX实例化后的对象,这个对象存放在中;
  • xxx作为引用变量名,而xxx指向中的new XXX();
  • 引用完成,xxx出栈,main()出栈,程序结束。

3.static关键字

由方法区的定义可知,被static关键字修饰的方法和变量是跟类一块加载的,
所以可以直接用类名.方法名()调用静态方法或者用类名.变量名调用静态变量。

public class Test {
    public static void main(String[] args) {
        Test.a(111);
        System.out.println(Test.b);
    }

    public static int a(int a) {
        return a;
    }
    
    static int b;
}

1、非静态方法可以调用静态方法,静态方法不能调用非静态方法。
2、执行顺序:

在这里插入图片描述


五、访问修饰符

在这里插入图片描述


六、Java的三大特性

1.封装

属性私有化(private),提供get/set方法。
特点:

1、提高程序的安全性,保护数据
2、隐藏代码细节。操作可以在get/set方法中实现,无需展示在公共类。
3、统一接口
4、增加系统的可维护性

2.继承

子类继承父类
特点:

1、用关键字extends来表示。
2、所有的类都默认继承于Object类
3、Java中只有单继承,没有多继承(一个子类只能有一个父类)。

Ctrl + H:idea中展示类之间的继承关系的快捷键

  • super

1、只能出现在子类的方法或者构造器中,调用父类的属性和方法。
2、super()必须在子类构造器的第一行。

  • super和this的区别

1、super指向父类对象,this指向本类对象。
2、super只能在继承中使用,而this可以在任一时候使用
3、super()调用父类构造,this()调用本类构造。super()和this()都必须在构造器的第一行,所以二者不存在于同一个构造器中。

  • 重写
    需要有继承关系,子类重写父类的方法

1、方法名、参数列表、返回值类型必须和父类相同,方法体不同。
2、子类重写父类方法时,使用的修饰符权限要大于等于父类方法的权限。
3、抛出的异常范围要小于等于父类方法的异常。

3.多态

存在条件:继承关系,方法需要重写,父类引用指向子类对象
多态是方法的多态,属性没有多态。

通过下面几个例子可以理解多态
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


七、abstract关键字

abstract修饰的类叫抽象类,修饰的方法叫抽象方法
1、抽象方法只有方法名,没有方法的实现。

public abstract class Test {
    //抽象方法
    public abstract void func1();
    public void func2(){

    }
    public abstract void func3();
}

2、抽象类的所有子类都必须重写父类中的抽象方法。除非这个子类也是抽象类。
在这里插入图片描述
3、不能new抽象类,只能靠子类去实现它。
在这里插入图片描述
4、抽象方法只能在抽象类中存在。


八、接口

interface,接口的本质是契约。

1.特点

1、接口中只有抽象方法,public abstract自动省略。
在这里插入图片描述
2、实现类中必须重写接口中所有的方法
在这里插入图片描述
3、接口是多继承
在这里插入图片描述
4、接口中定义的属性都是常量。
在这里插入图片描述
5、接口不能被实例化,因为接口中没有构造方法

2.抽象类与接口的对比

1、都不能被实例化。
2、抽象类中可以有抽象方法和普通方法;接口中只有抽象方法。
3、类是单继承,接口是多继承。


九、内部类

1.特点

1、在一个类中定义了一个类。
2、内部类可以直接访问外部类的成员,包括私有。
3、外部类要访问内部类的成员,必须创建对象。

在这里插入图片描述


2.成员内部类

在类的成员位置定义的类

在这里插入图片描述


3.局部内部类

在类的局部位置(方法里)定义的类,所以外界无法直接使用,需要在方法内部创建对象并使用
在这里插入图片描述


4.匿名内部类

1、前提:1存在一个类(具体类或者抽象类)或者接口
2、2/3本质是一个继承了该类或者实现了该接口的4子类匿名对象

在这里插入图片描述
3、调用内部类中的方法
在这里插入图片描述
在这里插入图片描述


十、泛型

1.概述

提供了编译时类型安全监测机制,该机制允许在编译时检测到非法的类型。

好处 :

1、把运行时期的问题提到了编译期间
2、避免了强制类型转换


2.泛型类、泛型方法、泛型接口

//泛型类
public class Generic<T> {
	private T t;
	
	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}
}

//泛型方法
public class Generic {
	public <T> void show(T t) {
		System.out.println(t);
	}
}

//泛型接口
public interface Generic<T> {
	void show(T t);
}

十一.克隆

1)原型模式

原型实例指定创建对象的种类,并且通过 复制/克隆/拷贝 这个原型来创建新的对象


2)浅克隆

克隆的是原型对象的地址,值会随着原型对象的成员变量的值改变
常用的方法:1、实现Cloneable接口;2、Arrays.copyOf()


3)深克隆

克隆的是原型对象的值,克隆对象和原型对象没有关联
常用的方法:1、实现Cloneable接口并重写clone();2、序列化;


异常和错误

在这里插入图片描述


常用类

一、Math

在这里插入图片描述


二、System

在这里插入图片描述


三、Object

Object是类层次结构的根,每个类都可以将Object作为超类。所有类都直接或间接的继承自该类。
构造方法:public Object()

为什么说子类的构造方法默认访问的是父类的无参构造方法?
它们的顶级父类只有无参构造。

1、toString()

public String toString()
默认输出地址。
源码描述:结果应该是一个简明扼要的表达,容易让人阅读, 建议所有子类覆盖此方法。

@Override
public String toString() {
	return "ObjectDemo{" +
	"age=" + age +
	", name='" + name + '\'' +
	'}';
}

2、equals()

public boolean equals(Object obj)
默认比较地址。与==类似.
可以通过重写来比较两者的内容

@Override
public boolean equals(Object o) {
	if (this == o) return true;
	if (o == null || getClass() != o.getClass()) return false;

	ObjectDemo that = (ObjectDemo) o;

	if (age != that.age) return false;
	return name != null ? name.equals(that.name) : that.name == null;
}

3.为什么重写equals()时要重写hashcode()?

默认情况下如果两个对象在通过equals()比较返回true,则hashcode()比较也相等
但两个对象值内容不同的情况下,hashcode的值也有可能相同,这就会造成哈希冲突。
所以必须重写hashchode()


四、Arrays

在这里插入图片描述


五、基本类型包装类

在这里插入图片描述

1.Integer

包装一个对象中的原始类型int的值
在这里插入图片描述
1、int和String的相互转换
int —> String
public static String valueOf(int i)

String —> int
public static int parseInt(String s)

public class IntegerDemo {
    public static void main(String[] args) {
        //int --> String
        int number = 100;
        //方式一:
        String s1 = "" + number;
        //方式二:
        //public static String valueOf(int i)
        String s2 = String.valueOf(number);

        //String --> int
        String s = "100";
        //方式一:
        //String --> Integer --> int
        Integer i = Integer.valueOf(s);
        //public int intValue()
        int x = i.intValue();
        //方式二:
        //public static int parseInt(String s)
        int y = Integer.parseInt(s);
    }
}

2.装箱与拆箱

在这里插入图片描述


六、日期类

1.Date

在这里插入图片描述

2.SimpleDateFormat

在这里插入图片描述
1)pattern的规定:
在这里插入图片描述
2)格式化 :从Date到String
public final String format(Date date):将日期格式化成日期/时间字符串
解析:从String到Date
public Date parse(String source):从给定字符串的开始解析文本以生成日期
在这里插入图片描述

3.Calendar

在这里插入图片描述

在这里插入图片描述


集合

一、Collection

public interface Collection<E> extends Iterable<E> {}

1.Collection的常用方法

在这里插入图片描述

在这里插入图片描述


2.Collection集合的遍历

Iterator:迭代器,集合的专用遍历方式

  • public interface Iterator<E> {}
  • Iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到。
  • 迭代器是通过集合的iterator()方法得到的,所以说迭代器是依赖于集合而存在的

Iterator中常用的方法:
E next():返回迭代中的下一个元素
boolean hasNext():如果迭代中具有更多元素,则返回true

public class IteratorDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> c = new ArrayList<>();

        //添加元素
        c.add("a");
        c.add("b");
        c.add("c");

        //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
        //通过集合对象获取迭代器对象
        Iterator<String> it = c.iterator();

        /*
            public Iterator<E> iterator() {
                return new Itr();
            }

            private class Itr implements Iterator<E> {
                ...
            }
         */

        //E next():返回迭代中的下一个元素
        System.out.println(it.next());  //a
        System.out.println(it.next());  //b
        System.out.println(it.next());  //c
        System.out.println(it.next());  //NoSuchElementException:表示被请求的元素不存在

        //boolean hasNext():如果迭代中具有更多元素,则返回true
        if (it.hasNext()) {
            System.out.println(it.hasNext());   //a
        }

        if (it.hasNext()) {
            System.out.println(it.hasNext());   //b
        }

        if (it.hasNext()) {
            System.out.println(it.hasNext());   //c
        }

        if (it.hasNext()) {
            System.out.println(it.hasNext());   //不输出
        }
        
        //用while循环改进判断
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

3.Collection为什么可以通过iterator遍历

1、Collection源码:

public interface Collection<E> extends Iterable<E> {}

2、Iterable源码:

public interface Iterable<T> {
	Iterator<T> iterator();
	default void forEach(Consumer<? super T> action) {
       Objects.requireNonNull(action);
       for (T t : this) {
           action.accept(t);
       }
   }
}

3、Iterator源码:

public interface Iterator<E> {
	boolean hasNext();
	E next();
	default void remove() {
       throw new UnsupportedOperationException("remove");
   }
}

结论:Iterable中封装了Iterator接口,只要实现了Iterable接口的类,就可以使用Iterator迭代器了。


二、List

1.List集合的特点

有序可重复
public interface List<E> extends Collection<E> {}

//创建List对象
//List是一个接口,无法直接实例化,只能实现类
List<String> list = new ArrayList<>();

//用迭代器遍历
Iterator<String> it =  list.iterator();
while (it.hasNext()) {
	String s = it.next();
	System.out.println(s);
}

//用for循环遍历
for (int i = 0; i < list.size(); i++) {
	String s = list.get(i);
	System.out.println(s);
}

2.List集合的常用方法

在这里插入图片描述


3.并发修改异常

用迭代器iterator遍历数组时,往数组中添加数据,会报并发修改异常ConcurrentModificationException

在这里插入图片描述

ConcurrentModificationException
产生原因:参考源码可知,迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致

  • 执行next()
    在这里插入图片描述
  • 执行add() 在这里插入图片描述

解决方案:用for循环遍历


4.ListIterator列表迭代器

允许程序员沿任意方向遍历列表

public interface ListIterator<E> extends Iterator<E> {
	boolean hasNext();
	E next();
	boolean hasPrevious();
	E previous();
}

E previous():返回列表中的上一个元素
boolean hasPrevious():反向遍历

在这里插入图片描述

用列表迭代器遍历集合,不会报ConcurrentModificationException(并发修改异常)
在这里插入图片描述

原因:根据源码分析,与ArrayList()中add()不同的是,在执行listIterator()下的add()时,在try…catch中会执行一遍
expectedModCount = modCount;
而不是modCount++
在这里插入图片描述


5.增强for循环

简化数组和Collection集合的遍历,内部原理是一个iterator迭代器

格式:
for(元素数据类型	变量名:数组和Collection集合) {
	在此处使用变量即可
}

public class ForDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        for (String s:list) {
            System.out.println(s);
        }
    }
}

6.LinkedList

在这里插入图片描述


7.List集合子类

  • ArrayList:底层是数组,查询快,增删慢。
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • LinkedList:底层是链表,查询慢,增删快,没有同步,线程不安全。
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable 
  • Vector:底层是数组,同步,线程安全
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • Array和ArrayList的区别
    可以将 ArrayList想象成一种会自动扩增容量的Array
    1)Array是指定固定大小的,而ArrayList可以自动扩容。
    2)Array中可以存储基本类型数据和对象类型 ,而ArrayList只能存储对象类型
    ArrayList对于基本数据类型,使用自动装箱,但牺牲了效率。内部就是使用”object[] _items;”这样一个私有字段来封装对象的
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

3)ArrayList类中的方法更多样化,比如说remove(),iteration()等


三、Set

1.Set集合的特点

public interface Set<E> extends Collection<E>

1、无序不可重复
2、没有带索引的方法,不能用普通for循环遍历

在这里插入图片描述


2.哈希值

JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
public int hashCode():返回对象的哈希码值

- 同一个对象调用多次hashCode()返回的哈希值相同。
- 默认情况下,不同对象的hash值是不同的,但可以通过重写hashCode()使其相同。
相同字符串的哈希值为什么相同?String类里重写了hashCode()方法

public int hashCode() {
	int h = hash;
	if (h == 0 && value.length > 0) {
		char val[] = value;

		for (int i = 0; i < value.length; i++) {
			h = 31 * h + val[i];
		}
		hash = h;
	}
	return h;
 }

- 某些字符串的hash值是相同的,可以自行百度。


3.哈希表

底层是数组+链表,可以说是一个元素为链表的数组
初始化默认长度为16

存储过程:(链地址法)
1、计算对象的哈希值;
2、哈希值%16,余数为哈希表中的位置;
3、若余数相同且哈希值不同,直接插入(链表的存储结构);
4、若哈希值相同,比较对象的内容,内容相同不插入,不相同则插入


4.HashSet集合

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

特点:

- 底层数据结构是哈希表
- 对集合的迭代顺序不作保证,也就是不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普通的for循环遍历
- 存储数据方式:先判断哈希值,若哈希值相同则调用equals方法。
-实现Set接口


5.HashSet集合保证元素唯一性源码分析

在这里插入图片描述
在这里插入图片描述


6.LinkedHashSet

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

特点:

1、继承自HashSet,实现Set接口
2、底层是哈希表+链表:链表保证有序,哈希表保证元素唯一


7.TreeSet

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
public interface NavigableSet<E> extends SortedSet<E>
public interface SortedSet<E> extends Set<E>   

特点:

1、实现NavigableSet接口,NavigableSet接口继承自SortedSet接口,SortedSet接口继承自Set接口
2、元素有序,此处的有序不是指存储和取出的顺序,而是按照一定规则进行排序,具体排序方式取决于构造器
public TreeSet():根据其元素的自然排序进行排序,比如String,包装类等默认按照从小到大的顺序遍历
public TreeSet(Comparator<? super E> comparator):根据指定的比较器进行排序

1)自然排序Comparable

详情参考此文章

2)比较器排序Comparator

Comparator:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3)treeSet总结

1、有两个构造器,一个是无参构造,一个是有参构造
2、调用无参构造,使用自然排序,需要在引用类型中实现Comparable接口
3、调用有参构造,使用Comparator比较器排序,构造器中传入的参数其实是Comparator接口的实现类对象


四、Map

1.Map的特点

public interface Map<K,V>   

1、Interface Map<K, V>K:键的类型 V:值的类型
2、将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值

在这里插入图片描述


2.Map集合的常用方法

在这里插入图片描述
在这里插入图片描述


3.Map集合的遍历

在这里插入图片描述


4.Map集合子类

  • Hashtable:同步,线程安全,继承自Dictionary实现Map接口,不允许key和value为null值,否则会报空指针异常
public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable
  • HashMap:没有同步,线程不安全,继承自AbstractMap类实现Map接口,允许key和value为null值
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable  

LinkedHashMap:底层是双向链表和哈希表

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V> 
  • TreeMap:红黑树对所有的key进行排序
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
public interface NavigableMap<K,V> extends SortedMap<K,V>
public interface SortedMap<K,V> extends Map<K,V>   

五、Collections

针对集合操作的工具类

public static <T extends Comparable<? super T>> void sort (List < T> list):将指定的列表按升序排列** public static void reverse(List<?> list):反转指定列表中元素的顺序
public static void shuffle(List<?> list):使用默认的随机源随机排列指定的列表
在这里插入图片描述


IO流

一、File

1.File类的构造器

1、文件和目录是可以通过File封装成对象的。
2、File封装的仅仅是一个路径名

在这里插入图片描述


2.File类创建功能

在这里插入图片描述
在这里插入图片描述


3.File类判断和获取功能

在这里插入图片描述
在这里插入图片描述


4.File类删除功能

在这里插入图片描述
删除的目录中如果有内容,需要先删除目录的内容,再删除目录


二、IO流概述

1、流:数据传输
2、IO流:处理设备间的数据传输问题
3、

在这里插入图片描述
4、分类

  • 按照数据流向分
    输入流:读数据
    输出流:写数据
  • 按照数据类型
    字节流:字节输入流(向内存读入数据)/字节输出流(从内存写出数据)
    字符流:字符输入流/字符输出流
    tips:如果数据通Windows自带的记事本软件打开,还可以读懂里面的内容,使用字符流,否则用字节流。默认使用字节流。

三、字节流

  • 字节流抽象基类
    InputStream:这个抽象类是表示字节输入流的所有类的超类
    OutputStream:这个抽象类是表示字节输出流的所有类的超类

1.字节流写数据

在这里插入图片描述


2.字节流写数据的三种方式

在这里插入图片描述
在这里插入图片描述


3.字节流写数据的两个问题

1、如何实现换行?
2、字节流写数据如何实现追加写入?
在这里插入图片描述


4.字节流读数据

1)一次读取一个字节

在这里插入图片描述

2)一次读取一个字节数组

在这里插入图片描述


5.字节缓冲流

  • 在内部创建了一个长度为8192的数组来存放数据,达到缓冲的作用,提高效率
  • 字节缓冲输出流:BufferedOutputStream(OutputStream out)
    在这里插入图片描述
  • 字节缓冲输入流:BufferedInputStream(InputStream in)
    在这里插入图片描述
    在这里插入图片描述
  • 为什么构造方法需要的是字节流,而不是具体的文件或者路径?
    字节缓冲流仅仅提供缓冲区,而真正的读写数据还需依靠基本的字节流对象进行操作

在这里插入图片描述


6.字节流总结

在这里插入图片描述


四、字符流

1.字符流的编码解码问题

在这里插入图片描述


2.字符流写数据的五种方式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


3.字符流读数据的两种方式

在这里插入图片描述
在这里插入图片描述


4.转换流的改进

转换流的名字较长,而常见的操作都是按照本地默认编码实现的。为了简化书写,转换流提供了对应的子类
涉及到编码和解码的问题,还是需要InputStreamReader、OutputStreamWriter

  • FileReader extends InputStreamReader:用于读取字符文件的便携类
public FileReader(String fileName) throws FileNotFoundException {
	super(new FileInputStream(fileName));
}
  • FileWriter extends OutputStreamWriter:用于写入字符文件的便携类
public FileWriter(String fileName) throws IOException {
	super(new FileOutputStream(fileName));
}

将fr.txt复制到fw.txt
在这里插入图片描述


5.字符缓冲流

  • BufferedWriter(Writer out),类似BufferedOutputStream
  • BufferedReader(Reader in),类似BufferedInputStream
字符缓冲流的特有功能
  • BufferedWriter:
    void newLine():写一个行分隔符,行分隔符字符串由系统属性定义(\r\n;\n;\r)
  • BufferedReader:
    public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符(无法换行),如果流的结尾已经到达,则为null

五、字节流和字符流总结

在这里插入图片描述
在这里插入图片描述


六、编码表

1.ASCII字符集

1、用于显示现代英语。主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
2、7位表示一个字符,共128个字符

2.GBXXX字符集

  • GB2312
    简体中文码表,一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,大约组合了包含7000多个简体汉字,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,被称为“全角”字符,而原来在127以下的字符被称为“半角”
  • GBK
    最常用的中文码表。在 GB2312标准基础上的拓展规范,使用了双字节编码方案,共收录了21003个汉字,同时支持繁体字以及日韩汉字等
  • GB18030
    最新的中文码表,收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持国内少数名族的文字,同时支持繁体字以及日韩汉字等

3.Unicode字符集

  • 为表达任意 语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码
  • UTF-8
    128个US-ASCII字符,只需一个字节编码
    拉丁文等字符,2个
    大部分常用字(含中文),3个
    其他极少使用的Unicode辅助字符,4个

七、特殊操作流

1.对象序列化流

对象写入文件

//ObjectOutputStream(OutputStream out)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件名"));

//创建对象
Student s = new Student("小明", 20);

//void writeObject(Object obj):将指定的对象写入ObjectOutputStream
oos.writeObject(s);

oos.close();

注意Student类要实现Serializable接口


2.对象反序列化流

从文件中读取到对象

//ObjectInputStream(InputStream in)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件名"));

//Object readObject():从ObjectInputStream读取一个对象
Object obj =  ois.readObject();

Student s = (Student) obj;
System.out.println(s.getName() + "," + s.getAge());

ois.close();

3.serialVersionUID&transient

1、用对象序列化流序列化了一个对象后,如果修改了对象所属的类文件,读取数据的时候会出问题吗?
会抛出一个异常:InvalidClassException。因为在序列化运行时,会与每个可序列化的类关联一个serialVersionUID,若修改了该类,反序列化时产生的serialVersionUID与序列化时的不匹配,则会报异常
2、如何解决上述问题?
给对象所属的类加一个值:

private static final long serialVersionUID = 42L;

3、如果一个对象中的某个成员变量的值不想被序列化怎么实现?
给该成员变量添加一个transient 关键字,使其不参与序列化过程

private transient int age;

4.Properties

HashTable的一个子类。也是线程安全的Map集合

1)Properties的使用

在这里插入图片描述

2)Properties特有的方法

在这里插入图片描述
在这里插入图片描述

3)Properties与IO流结合的方法

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值