• Java SE 容易忘记的点记录


    Java SE 容易忘记的点记录

    1. 访问权限

    关键字privatedefaultprotectedpublic
    同一类
    同一包中的类
    子类
    其他包中的类

    一个成员对象会在哪些地方被访问呢,首先是自己类的方法、代码块等地方,这时候无论什么权限都是可以进行访问的。
    其次就是其他类中,通过成员对象所在类的实例进行访问,这时其他类相较于所在类就会出现两种情况,一个是在同一个包内,一个是不在同一个包内,这时只有private关键字对这种情况进行区分,不在同一个包内是无法访问private关键字修饰的成员变量的。
    最后就是当这个类被继承后,子类是否能访问该成员变量,使用protected进行约束,public和protected是可以访问的,而default和private是无法访问的。
    方法的权限控制与方法是相同的。

    而类的权限控制只有public和default两种,内部类除外,内部类四种都是可以进行设置的。

    public

    使用public进行权限修饰的时候是在任何地方都可以访问的

    default

    使用default时只能在同一包下进行访问,同一包下的另一个类继承这个类时,也是无法直接使用这个变量或者方法的,这个时候是按照子类的权限进行判断的,而同一包下这个含义指的是能否通过实例直接通过.进行访问。

    protected

    相比于default多了子类可以访问,就是子类继承之后可以直接使用这个变量

    public

    对比protected多了包外访问的权限。

    2. 一维数组

    三种初始化方式

    int[] list = new int[10];
    int[] list1 = {1,2,3};
    int[] list2 = new int[]{1,2,3};
    
    • 1
    • 2
    • 3

    内容

    数组是一个类,拥有Object中的所有方法,都是可以使用的,并且含有成员变量length,并且length时final的,在初始化时会为length赋值,因此组数在初始化之后时定长的,长度无法改变。可以创建一个需要的长度的数组重新赋值给这个引用。

    int[] list = new int[10];
    // ...
    list = new int[20];
    
    • 1
    • 2
    • 3

    数组的遍历

    有两种方法,其实就是两种for循环

    for(int i = 0;i < list.length; i++){
    	list[i] // ...
    }
    
    for(int i : list){
    	i // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    第二种称为foreach,foreach的存在是有优势,但同样是存在劣势的,当你的for循环中指进行读取操作的时候,foreach简洁的风格,简易的代码是很好用的。但是foreach中无法对数组中的值进行修改,需要修改的时候需要使用第一种循环哦。

    二维数组

    初始化

    int[][] ll = new int[3][];
    int[][] ll1 = {{1,2}};
    int[][] ll2 = new int[][]{{1,2},{2,2,2,2,2}};
    
    • 1
    • 2
    • 3

    初始化和一维数组类似,可以直接用一个已经确定的二维数组进行赋值,也可以直接new,但是第二种方法和一维数组一样,只能在初始化时进行使用。

    遍历

    其实就是两层的遍历,第一层得到的是一个int[]类型的,第二层是int

    for (int[] i : ll) {
    	for (int j : i) {
    		// 操作
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    java 三大特征:继承、封装、多态

    多态中需要注意instanceof、final类

    内部类

    存在在一个类里面的类就叫内部类,根据所处位置的不同、约束的不同,给内部类又取了不同的名字

    成员内部类

    public class Test {
        class Inner{   //类中定义的一个内部类
            
        }
    }
    public static void main(String[] args) {
        Test test = new Test();
        Test.Inner inner = test.new Inner();   //写法有那么一丝怪异,但是没毛病!
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    静态内部类

    public class Test {
        static class Inner{
    
        }
    }
    
    public static void main(String[] args) {
        Test.Inner inner = new Test.Inner();   //不用再创建外部类对象了!
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    静态内部类并不是创建了一个类大家共用,而是可以直接用类名进行new

    局部内部类

    public class Test {
        public void test(){
            class Inner{
    
            }
            
            Inner inner = new Inner();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    匿名内部类

    public static void main(String[] args) {
        Eat eat = new Eat() {
            @Override
            public void eat() {
                //DO something...
            }
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    枚举类

    本质上还是一个普通类,编译器做了优化,可以像正常类一样写对象、方法等,但是第一行需要输入的内容是枚举类的类别,即使一个状态都不存在也需要输入一个分号。
    在枚举类第一行中声明的状态在编辑之后都会得到当前类的一个静态常量,并且使用的时候其实也是一个对象。
    若枚举类的默认构造器被覆盖,则在第一行创建状态的时候需要用括号调用新的构造器。
    并且Enum自带了一些方法,其中valueof用于将字符串转化为状态,values为返回所有状态的一个集合。

    异常

    异常分为 编译时异常Exception运行时异常RuntimeException
    其中 Exception必须要求在编写代码期间通过try-catch进行捕获,可以是对异常进行处理,也可以再一次抛出,我觉得这里是否抛出throw的逻辑是,当前在写的方法是提供给他人调用的,还是该方法已经到处理实际逻辑阶段了,若是对可能发生异常方法的一层封装,那么抛出可能是比较合理的操作,由上层的调用者对异常进行合适的处理,而到实际逻辑处理阶段直接进行处理是比较合理的,否则可能会引起程序的中断运行。
    Runtime Exception是可以不进行捕获的,但是一些常见的数组越界、除数为0等需要在编程的时候注意。

    对于的异常的捕获try-catch,最重要的其实是保证程序的正常运行。

    try-catch-finally的运行顺序是:首先运行try,若发生异常则运行catch,无论是否发生异常最后会运行finally,即使在try中已经return,同样会调用finally中程序。

    当jdk提供的异常不够用时,我们可以自定义异常,一般定义的都是Exception,继承Exception类就可以,记得重写相应的构造方法哦!

    范型

    范型本质上并不是JVM支持的语法,而是一种语法糖,在编译期间帮助你检查参数类型是否正确的一种手段,并且在编译中会进行类型擦除,实际在字节码文件中是不存在范型的。
    一般需要使用范型地方是一个地方可能使用两种及以上类型的时候会使用范型,例如容器,在编写容器代码的时候并没有针对某一种类型进行来写代码,并且在使用时可以向容器中放入使用者所要求的类型的对象,这就是范型的作用。

    二叉树

    二叉树是一种搜索树,顾名思义是用于搜索用的,所有二叉树有别于树,树是不带有左右之分的,但是二叉树因为是用于搜索,所以进行了左右的区分。
    为什么要用二叉树进行搜索呢?主要是因为线性结构存在弊端,线性表在有序的情况下可以通过二分查找的方式进行搜索,但是在维护有序是的代价太够,插入和删除并不是线性表所擅长的,而链表则呈现了完全相反的特点,插入和删除十分的方便但是搜索只能进行线性的搜索,是在不够优秀。
    由此就想到了树的结构进行存储与搜索,其实二分查找本质上就是一个平衡二叉树,不过这个查找与搜索的工作是在线性表中完成的。
    二叉树的特点是每一层只比较一次,因此二叉树的时间复杂度与深度相关,普通二叉树可能会遇到插入时是线性的情况下,导致整树趋向于线性的存在,横向的空间没有充分利用。
    因此提出了平衡二叉树,平衡二叉树要求每一个节点的左右子树高度差小于等于1,这个要求带来的好处是搜索非常迅速,横向空间充分利用,但随之而来的缺点就是插入和删除子节点的时候,需要进行大量的调整才能使得二叉树平衡。
    在这种条件下就提出了红黑树
    在这里插入图片描述
    上图是红黑树调整的情况,根据红黑树的限制,黑节电是多于红节点的,并且插入时新节点为红节点,只有父节点是红色时才会进行平衡操作,所以在红黑树中调整操作是得以减少的。并且性能与平衡二叉树是类似的,所以很多地方都会选择红黑树而不是平衡。

    容器

    集合类最顶层不是抽象类而是接口,因为接口代表的是某个功能,而抽象类是已经快要成形的类型,不同的集合类的底层实现是不相同的,同时一个集合类可能会同时具有两种及以上功能(既能做队列也能做列表),所以采用接口会更加合适,接口只需定义支持的功能即可。

    继承关系图

    在这里插入图片描述
    图中展示了容器之间的一个继承关系,下面介绍一下总结结构,collection接口使用了iterable接口,这个接口的主要作用是实现了for-each循环以及迭代器的功能,listset是具有迭代器的,但是map是没有实现这个方法的。
    一般在使用的时候List list = new ArrayList<>();这种方式实现,所以最常用的就是ListSetMap三个接口中要求子类实现的方法,而实际实现类中还会根据实现原理不同,提供一些独有的方法。

    collection接口表示的是集合,其中List表示可重复集合,而Set表示的是不可重复集合,其中常用的ListArrayListLinkedList,其中LinkedList实现类Queue接口,可以当作队列进行使用。常用的SetHashSetTreeSet,并且Set底层是通过Map实现的。相同的Map中提供的实现与Set类似,是TreeMapHashMap

    咱这次先不讲具体某一个方法的实现原理,先介绍一下三个接口具体有哪些方法。

    List

    方法作用
    int size()返回集合中的元素数量
    boolean isEmpty()判断集合是否为空
    boolean contains(Object o)集合中是否包含某一个元素
    Object[] toArray()返回由集合中所有的元素组成的新创建的数组
    T[] toArray(T[] a)将集合中的元素按照指定类型构造新的集合后返回
    boolean add(E e)添加元素
    void add(int index, E element)在指定位置插入元素
    boolean addAll(Collection c)向集合中添加给定集合中的所有元素
    boolean addAll(int index, Collection c)将指定集合中的所有元素插入到指定位置
    boolean remove(Object o)移除指定元素
    E remove(int index)移除指定位置的元素
    boolean removeAll(Collection c)从此列表中删除包含在指定集合中的所有元素
    boolean removeIf(Predicate filter)删除此集合中满足给定谓词的所有元素
    boolean retainAll(Collection c)从这个列表中删除所有不包含在指定集合中的元素
    void clear()清除所有元素
    E set(int index, E element)设置置顶位置的元素
    void replaceAll(UnaryOperator operator)将此列表的每个元素替换为将运算符应用于该元素的结果
    void sort(Comparator c)对集合中的元素进行排序
    E get(int index)获取指定位置的元素
    boolean containsAll(Collection c)如果此列表包含指定集合的所有元素,返回true
    Stream stream()返回以此集合为源的顺序流
    List subList(int fromIndex, int toIndex)返回此列表在指定 fromIndex(包括)和 toIndex(不包括)之间部分的视图
    int indexOf(Object o)返回给定元素的位置
    int lastIndexOf(Object o)返回给定元素最后一次出现的位置索引
    ListIterator listIterator()迭代器
    ListIterator listIterator(int index)从给定位置开始的迭代器

    在这里插入图片描述

    Set

    方法作用
    int size()返回集合中的元素数量
    boolean isEmpty()判断集合是否为空
    Object[] toArray()返回由集合中所有的元素组成的新创建的数组
    T[] toArray(T[] a)将集合中的元素按照指定类型构造新的集合后返回
    boolean add(E e)添加元素
    void add(int index, E element)在指定位置插入元素
    boolean addAll(Collection c)向集合中添加给定集合中的所有元素
    boolean remove(Object o)移除指定元素
    E remove(int index)移除指定位置的元素
    boolean removeAll(Collection c)从此列表中删除包含在指定集合中的所有元素
    boolean removeIf(Predicate filter)删除此集合中满足给定谓词的所有元素
    boolean retainAll(Collection c)从这个列表中删除所有不包含在指定集合中的元素
    void clear()清除所有元素
    boolean contains(Object o)集合中是否包含某一个元素
    boolean containsAll(Collection c)如果此列表包含指定集合的所有元素,返回true
    Stream stream()返回以此集合为源的顺序流
    Iterator iterator()迭代器

    Set相对List而言没有没有这么多自己的方法了。在Idea中可以看到方法的继承关系,List中由很多属于自己的方法,并不是继承而来的,因为List的实现原理是线性表和链表两种,都可以通过index对元素进行定位。
    Set是通过Map实现的,Map的底层是Tree和Hash这两种都是无法通过index进行索引访问的,因此在Set中的使用过程中一般都是通过迭代器来访问整个容器,或者通过contains方法判断是否包含某一个元素。
    在这里插入图片描述

    Map

    方法作用
    int size()返回集合中的元素数量
    boolean isEmpty();映射集是否为空
    boolean containsKey(Object key)此映射集是否包含指定键的映射
    boolean containsValue(Object value)此映射集是否将一个或多个键映射到指定值
    V get(Object key)根据键返回值
    V put(K key, V value)在映射集中插入键值对
    V remove(Object key)根据Key删除键值对
    void putAll(Map m)将另一个映射集中的所有元素插入到当前映射集
    void clear()清空所有元素
    Set keySet()返回此映射中包含的键的 Set 视图
    Collection values()返回此映射中包含的值的集合视图
    Set> entrySet()返回此映射中包含的映射的 Set 视图
    V getOrDefault(Object key, V defaultValue)返回指定键映射到的值,如果此映射不包含该键的映射,则返回 defaultValue
    void replaceAll(BiFunction function)将每个条目的值替换为对该条目调用给定函数的结果
    V putIfAbsent(K key, V value)如果指定的键尚未与值关联,则将其与给定值关联并返回 null,否则返回当前值
    boolean remove(Object key, Object value)仅当当前映射到指定值时,才删除指定键的条目
    boolean replace(K key, V oldValue, V newValue)根据Key将旧值替换为新值
    V replace(K key, V value)根据Key将旧值替换为新值

    在这里插入图片描述
    掌握一下基本的增删改查的方法,并且知晓不同实现情况下,擅长和不擅长的操作,在使用过程中使用何种情况更为合适。

    Stream

    optional

    Array工具类

    Java提供了一个Array工具类给数组使用,下面介绍一下其中提供的方法。
    这个类是一个工具类,并且将构造方法私有话了,提供的方法均为静态的,因此不需要也无法创建对象,之间使用方法即可。其中很多方法都针对基本数据类型和引用类型都做了实现。

    方法作用
    List asList(T… a)将一个数组转化为集合进行返回
    int binarySearch(byte[] a, byte key)使用二分查找在集合中搜索给定值的下标位置
    boolean[] copyOf(boolean[] original, int newLength)创建一个指定长度的新数组,并且将现有的数据存入其中
    deepEquals(Object[] a1, Object[] a2)判断两个数组的深度是否相同
    boolean equals(boolean[] a, boolean[] a2)判断两个数组是否相同
    void fill(boolean[] a, boolean val)将指定的值填入数组中的每一个位置
    int hashCode(boolean a[])根据数组内容返回hash值
    void parallelSort(byte[] a)将指定的数组生序排序
    void sort(byte[] a)排序
    String toString(boolean[] a)转化为字符串

    流的分类
    Java在java.io包中提供了大量的流类,但是均为下面首先要讲的四个抽象类的子类,规范了每个类需要实现的功能。

    InputStream

    MAX_SKIP_BUFFER_SIZE用于确定跳过时使用的最大缓冲区大小。
    int read()从输入流中读取数据的下一个字节。值字节作为 int 返回,范围为 0 到 255。如果由于到达流的末尾而没有可用的字节,则返回值 -1。此方法会一直阻塞,直到输入数据可用、检测到流结束或引发异常
    int read(byte b[], int off, int len)从输入流中读取最多 len 个字节的数据到一个字节数组中
    long skip(long n)跳过并丢弃此输入流中的 n 字节数据
    int available()返回可以从此输入流中读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。用于猜测后面还有多少字节,一般读取文本之类的不存在估计错误的情况,但是网络相关的可能因为延迟等出现问题。
    void close()关闭流
    void mark(int readlimit)标记此输入流中的当前位置。对 reset 方法的后续调用将此流重新定位到最后标记的位置,以便后续读取重新读取相同的字节。
    void reset()回到之前标记的地方重新读
    boolean markSupported()测试此输入流是否支持 mark 和 reset 方法。是否支持标记和重置是特定输入流实例的不变属性。 InputStream 的 markSupported 方法返回 false

    在这里插入图片描述

    OutputStream

    void write(int b) 将指定字节写入此输出流。写入的一般约定是将一个字节写入输出流
    void flush()刷新此输出流并强制写出任何缓冲的输出字节
    void close()关闭流
    在这里插入图片描述

    Reader

    int read(java.nio.CharBuffer target)尝试将字符读入指定的字符缓冲区
    int read()读取单个字符。此方法将阻塞,直到字符可用、发生 IO 错误或到达流的末尾
    long skip(long n)跳过字符
    boolean ready()告诉这个流是否准备好被读取
    boolean markSupported()告知此流是否支持 mark() 操作
    void mark(int readAheadLimit)标记
    void reset()回到标记
    在这里插入图片描述

    Writer

    void write(int c) 写入单个字符
    Writer append(CharSequence csq)将指定的字符序列附加到此编写器
    void flush()刷新此输出流并强制写出任何缓冲的输出字节
    void close()关闭流
    在这里插入图片描述

  • 相关阅读:
    MATLAB实现的数字图像处理(指纹增强)
    docker基础知识
    【Spring Cloud Alibaba】9 - OpenFeign集成Sentinel实现服务降级
    nmcli 命令行设置 ipv4 ipv6 ip 网关等
    特征筛选还在用XGB的Feature Importance?试试Permutation Importance
    Matplotlib(一)
    Problem A: 检查数中重复的数字
    1.1.4:DHTMLX Rich Text|JavaScript/HTML Rich Text Editor
    什么是WebRTC?
    Android获取系统读取权限
  • 原文地址:https://blog.csdn.net/weixin_43383406/article/details/126220883