java薄弱基础知识记录


所有内容为对“廖雪峰java”的整理

总结了我认为需做笔记的地方

  • 用final修饰的类不能被继承
  • 对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。
  • 到底什么是方法签名呢? 通过指定方法的访问级别(例如 public 或private)、可选修饰符(例如abstract 或sealed)、返回值、名称和任何方法参数,可以在类或 结构中声明方法。 这些部分统称为方法的“签名”。 为进行方法重载,方法的返回类型不是方法签名的一部分。

基础知识

  1. java程序基础:
    • 变量、数据类型:整形(int、long、short、byte)
                      浮点型(double、float)
                      字符型(char)
                      布尔型(bool)
                      引用型(除以上基本类型外,都是引用类型:引用类型的变量类似于C语言的指针,它内部存储一个“地址”,指向某个对象在内存的位置)
    • 常量:变量的时候,如果加上final修饰符,这个变量就变成了常量
    • var变量:使用var定义变量,仅仅是少写了变量类型而已,编译器会自动推断变量类型。例如:var sb = new StringBuilder();
    • 类型的概念:
      • 数据类型是和数据结构密切相关的,它是:值的集合和定义在这个值集上的一组操作的总称。分为原子类型和结构类型。
    • 转义字符:
      " 表示字符"
      ’ 表示字符’
      \ 表示字符
      \n 表示换行符
      \r 表示回车符
      \t 表示Tab
      \u#### 表示一个Unicode编码的字符
  2. 面向对象程序设计:
    • 方法:固定参数、可变参数、参数绑定
    • 构造方法:可以定义多个构造方法,在通过new操作符调用的时候,编译器通过构造方法的参数数量、位置和类型自动区分。
    • 方法重载:目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。
    • 继承:继承树、super、向上转型、向下转型(同类型,利用instanceof,在向下转型前可以先判断)、区分继承和组合
    • 多态:在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super来调用。用final修饰的方法不能被Override。
    • 抽象类:abstract
    • 接口:interface、default方法
    • 静态字段和静态方法
    • 作用域:全局变量、局部变量、public、private、protected、final、一个java文件只能有一个public签名(修饰符)
    • 内部类:Inner Class、Anonymous(匿名) Class、Static Nested Class
    • classPath:classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索class
    • jar:强烈不推荐在系统环境变量中设置classpath,那样会污染整个系统环境。在启动JVM时设置classpath才是推荐的做法。实际上就是给java命令传入-classpath或-cp参数。
        /META-INF/MANIFEST.MF(存放class信息,就不用JVM命令行参数了)
    • class版本:javac --source 9 --target 11 Main.java
    • 模块:自带“依赖关系”的class容器就是模块(jmods);
        编写模块(项目中必须有module-info.java);
        运行模块(java --module-path hello.jar --module hello.world);
        打包jre(在当前目录下,我们可以找到jre目录,这是一个完整的并且带有我们自己hello.jmod模块的JRE);
        访问权限:class的这些访问权限只在一个模块内有效,模块和模块之间,例如,a模块要访问b模块的某个class,必要条件是b模块明确地导出了可以访问的包(module-info.java中编写如下代码)。
      module java.xml {
          exports java.xml;
          exports javax.xml.catalog;
          exports javax.xml.datatype;
          ...
      }
      
  3. java核心类
    • 字符串string:两个字符串比较,必须总是使用equals()方法。System.out.println(s1.equals(s2));
      • 字符串声明方式及原理:java字符串声明方式区别1java中堆栈和常量池详解|区别2
        java常量池和堆空间的区别堆和池java虚拟机讲区别
      • 比较:想要比较两个字符串是否相同时,要特别注意,我们实际上是想比较字符串的内容是否相同。必须使用equals()方法而不能用==;要忽略大小写比较,使用equalsIgnoreCase()方法。
      • 以下详见:
      • 是否包含字符串/提取子串
      • 字符索引
      • 去除首尾空白字符trim()、strip()
      • 替换字符串replace
      • 分割字符串splice
      • 拼接字符串join
      • 格式化字符串formatted()、format()
      • 类型转换:String.valueOf(123); Integer.parseInt(“123”); Boolean.parseBoolean(“true”); “Hello”.toCharArray();
      • 字符编码:
        byte[] b1 = "Hello".getBytes(); // 按系统默认编码转换,不推荐
        byte[] b2 = "Hello".getBytes("UTF-8"); // 按UTF-8编码转换
        byte[] b2 = "Hello".getBytes("GBK"); // 按GBK编码转换
        byte[] b3 = "Hello".getBytes(StandardCharsets.UTF_8); // 按UTF-8编码转换
        
    • stringbuilder:为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象。append()、delete()方法。
    • StringJoiner:add方法  String.join()(在内部使用了StringJoiner来拼接字符串,在不需要指定“开头”和“结尾”的时候,用String.join()更方便)
    • 包装类型:想要把int基本类型变成一个引用类型,我们可以定义一个Integer类,它只包含一个实例字段int,这样,Integer类就可以视为int的包装类(Wrapper Class)。
          直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing),反过来,把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)
          所有的包装类型都是不变类(final)。
          进制转换:
      System.out.println(Integer.toString(100)); // "100",表示为10进制 System.out.println(Integer.toString(100, 36)); // "2s",表示为36进制 System.out.println(Integer.toHexString(100)); // "64",表示为16进制 System.out.println(Integer.toOctalString(100)); // "144",表示为8进制 System.out.println(Integer.toBinaryString(100)); // "1100100",表示为2进制
          整数和浮点数的包装类型都继承自Number
    • javaBean:有私有属性的字段和读getter写setter方法的类。
          作用:JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。此外,JavaBean可以方便地被IDE工具分析,生成读写属性的代码,主要用在图形界面的可视化设计中。
          枚举javaBean属性:使用Introspector.getBeanInfo()可以获取属性列表。
    • 枚举类:java枚举类型是一种基本数据类型而不是构造数据类型,而在C语言等计算机编程语言中,它是一种构造数据类型。 枚举类型用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。 定义:是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。
          enum:为了让编译器能自动检查某个值在枚举的集合内,并且,不同用途的枚举需要不同的类型来标记,不能混用,我们可以使用enum来定义枚举类。其次,不可能引用到非枚举的值,因为无法通过编译。最后,不同类型的枚举不能互相比较或者赋值,因为类型不符。
          enum比较:使用enum定义的枚举类是一种引用类型(类)。因为enum类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==比较。
          enum类型:
              定义的enum类型总是继承自java.lang.Enum,且无法被继承;
              只能定义出enum的实例,而无法通过new操作符创建enum的实例;
              定义的每个实例都是引用类型的唯一实例;
              可以将enum类型用于switch语句。
          name():返回枚举的名称常量名
          ordinal():返回定义的常量的顺序,从0开始计数。要编写健壮的代码,就不要依靠ordinal()的返回值。因为enum本身是class,所以我们可以定义private的构造方法,并且,给每个枚举常量添加字段
          switch:因为枚举类天生具有类型信息和有限个枚举常量,所以比int、String类型更适合用在switch语句中
    • 记录类:使用record(通常用于定义数据类)定义的是不变类(类和字段final)。构造方法、可以编写Compact Constructor对参数进行验证、可编写静态方法of()。和enum类似,我们自己不能直接从Record派生,只能通过record关键字由编译器实现继承
    • BigInteger:BigInteger用于表示任意大小的整数;BigInteger是不变类,并且继承自Number;将BigInteger转换成基本类型时可使用longValueExact()等方法保证结果准确。
    • BigDecimal:BigDecimal用于表示精确的小数,常用于财务计算;比较BigDecimal的值是否相等,必须使用compareTo()而不能使用equals()
    • 常用工具类:Math:数学计算、Random:生成伪随机数、SecureRandom:生成安全的随机数

面向抽象编程

  • 当我们定义了抽象类Person,以及具体的Student、Teacher子类的时候,我们可以通过抽象类Person类型去引用具体的子类的实例:这种尽量引用高层类型,避免引用实际子类型的方式,称之为面向抽象编程。
  • 面向抽象编程的本质就是:
    • 上层代码只定义规范(例如:abstract class Person);
    • 不需要子类就可以实现业务逻辑(正常编译);
    • 具体的业务逻辑由不同的子类实现,调用者并不关心。
  • 位于同一个包的类,可以访问包作用域的字段和方法。不用public、protected、private修饰的字段和方法就是包作用域。

异常处理

  • 捕获异常try catch finally 捕获多种异常
  • 抛出异常:创建某个Exception的实例;用throw语句抛出。调用printStackTrace()可以打印异常的传播栈,对于调试非常有用。通常不要在finally中抛出异常。如果在finally中抛出异常,应该原始异常加入到原有异常中。调用方可通过Throwable.getSuppressed()获取所有添加的Suppressed Exception。
    • 屏蔽异常:这说明finally抛出异常后,原来在catch中准备抛出的异常就“消失”了,因为只能抛出一个异常。没有被抛出的异常称为“被屏蔽”的异常(Suppressed Exception)。
  • 自定义异常
  • NullPointerException空指针异常:
    • NullPointerException是Java代码常见的逻辑错误,应当早暴露,早修复;
    • 可以启用Java 14的增强异常信息来查看NullPointerException的详细错误信息。
  • 断言(assert):断言是一种调试方式,断言失败会抛出AssertionError,只能在开发和测试阶段启用断言;对可恢复的错误不能使用断言,而应该抛出异常;断言很少被使用,更好的方法是编写单元测试。
    • TS类型断言定义:把两种能有重叠关系的数据类型进行相互转换的一种 TS 语法,把其中的一种数据类型转换成另外一种数据类型。
  • JDK logging:
    • 日志是为了替代System.out.println(),可以定义格式,重定向到文件等;
    • 日志可以存档,便于追踪问题;
    • 日志记录可以按级别分类,便于打开或关闭某些级别;
    • 可以根据配置文件调整日志,无需修改代码;
    • Java标准库提供了java.util.logging来实现日志功能。
  • Commons Logging:
    • Commons Logging是一个第三方日志库,它是由Apache创建的日志模块。Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging。
    • Commons Logging可以自动检测并使用其他日志模块。
    • Commons Logging日志级别:FATAL、ERROR、WARNING、INFO、DEBUG、TRACE
  • log4j:Log4j是一个组件化设计的日志系统,它的架构大致如下:
    ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
    ├──>│ Appender │───>│ Filter │───>│ Layout │───>│ Console │
    │ └──────────┘ └──────────┘ └──────────┘ └──────────┘

    │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
    ├──>│ Appender │───>│ Filter │───>│ Layout │───>│ File │
    │ └──────────┘ └──────────┘ └──────────┘ └──────────┘

    │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
    └──>│ Appender │───>│ Filter │───>│ Layout │───>│ Socket(通过网络输出到远程计算机)
    └──────────┘ └──────────┘ └──────────┘ └──────────┘
    当我们使用Log4j输出一条日志时,Log4j自动通过不同的Appender把同一条日志输出到不同的目的地。
  • SLF4J和LogBack:其实SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现。始终使用SLF4J的接口写入日志,使用Logback只需要配置,不需要修改代码。

反射

反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用其方法。

  • Class类:由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。这种通过Class实例获取class信息的方法称为反射(Reflection)。
    • 动态加载:当执行Main.java时,由于用到了Main,因此,JVM首先会把Main.class加载到内存。然而,并不会加载Person.class,除非程序执行到create()方法,JVM发现需要加载Person类时,才会首次加载Person.class。如果没有执行create()方法,那么Person.class根本就不会被加载。
  • 访问字段:
    Field getField(name):根据字段名获取某个public的field(包括父类)
    Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
    Field[] getFields():获取所有public的field(包括父类)
    Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
  • 调用方法:
    Method getMethod(name, Class…):获取某个public的Method(包括父类)
    Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
    Method[] getMethods():获取所有public的Method(包括父类)
    Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
  • 调用构造方法:
    getConstructor(Class…):获取某个public的Constructor;
    getDeclaredConstructor(Class…):获取某个Constructor;
    getConstructors():获取所有public的Constructor;
    getDeclaredConstructors():获取所有Constructor。
  • 获取继承关系:
    Class getSuperclass():获取父类类型;
    Class[] getInterfaces():获取当前类实现的所有接口。
  • 动态代理:动态代码,我们仍然先定义了接口Hello,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。

注解Annotation

  • 第一类是由编译器使用的注解,这类注解不会被编译进入.class文件,它们在编译后就被编译器扔掉了。
  • 第二类是由工具处理.class文件使用的注解,比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊的功能。这类注解会被编译进入.class文件,但加载结束后并不会存在于内存中。这类注解只被一些底层库使用,一般我们不必自己处理。
  • 第三类是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。例如,一个配置了@PostConstruct的方法会在调用构造方法后自动被调用(这是Java代码读取该注解实现的功能,JVM并不会识别该注解)。
  • 注解可以配置参数
  • 定义注解public @interface Report
    • 元注解:有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)
  • 使用注解:使用反射API读取Annotation;注解的作用(个人认为):检查

泛型

  • T是任意一种类
  • 泛型就是定义一种模板,例如ArrayList,然后在代码中为用到的类创建对应的ArrayList<类型
  • 注意泛型的继承关系:可以把ArrayList向上转型为List(T不能变!),但不能把ArrayList向上转型为ArrayList(T不能变成父类)。
  • 使用、编写:多个泛型类型
  • 擦拭法:Java语言的泛型实现方式是擦拭法(Type Erasure)。所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
    • first = new T();
      last = new T();
      擦拭后实际上变成了:
      first = new Object();
      last = new Object();
    • 局限一:不能是基本类型,例如int,因为实际类型是Object,Object类型无法持有基本类型
    • 局限二:无法取得带泛型的Class。
    • 局限三:无法判断带泛型的类型
    • 局限四:不能实例化T类型;
    • 要实例化T类型,我们必须借助额外的Class参数。
    • 一个类可以继承自一个泛型类。例如:父类的类型是Pair,子类的类型是IntPair,可以这么继承
  • extends通配符:限制T
  • super通配符:扩展
  • 反射和泛型:Java的部分反射API也是泛型。例如:Class就是泛型。。
    • 谨慎使用泛型可变参数:static T[] asArray(T… objs)

集合

  • List:在集合类中,List是最基础的一种集合:它是一种有序列表。List是一种有序链表:List内部按照放入元素的先后顺序存放,并且每个元素都可以通过索引确定自己的位置。
  • equals():在List中查找元素时,List的实现类通过元素的equals()方法比较两个元素是否相等,因此,放入的元素必须正确覆写equals()方法,Java标准库提供的String、Integer等已经覆写了equals()方法;
  • Map:Map是一种映射表,可以通过key快速查找value
  • 编写equals、hashcode:list、map必须正确覆写equals()方法。
    • 思考一下HashMap为什么能通过key直接计算出value存储的索引。相同的key对象(使用equals()判断时返回true)必须要计算出相同的索引,否则,相同的key每次取出的value就不一定对。
    • 通过key计算索引的方式就是调用key对象的hashCode()方法,它返回一个int整数。HashMap正是通过这个方法直接定位key对应的value的索引,继而直接返回value。
  • enumMap:如果作为key的对象是enum类型,那么,还可以使用Java集合库提供的一种EnumMap,它在内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引,并不需要计算hashCode(),不但效率最高,而且没有额外的空间浪费。
    • 使用EnumMap的时候,根据面向抽象编程的原则,应持有Map接口。
  • TreeMap:还有一种Map,它在内部会对Key进行排序,这种Map就是SortedMap。注意到SortedMap是接口,它的实现类是TreeMap。
  • Properties:Properties设计的目的是存储String类型的key-value,但Properties实际上是从Hashtable派生的,它的设计实际上是有问题的,但是为了保持兼容性,现在已经没法修改了。除了getProperty()和setProperty()方法外,还有从Hashtable继承下来的get()和put()方法,这些方法的参数签名是Object,我们在使用Properties的时候,不要去调用这些从Hashtable继承下来的方法。
    • 用于程序中配置文件的实时编写,或配置文件单独编写
  • Set:如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。
    在这里插入图片描述
  • Quenue
  • PriorityQueue优先级队列:
    • PriorityQueue实现了一个优先队列:从队首获取元素时,总是获取优先级最高的元素。
    • PriorityQueue默认按元素比较的顺序排序(必须实现Comparable接口),也可以通过Comparator自定义排序算法(元素就不必实现Comparable接口)。
  • Deque:允许两头都进,两头都出,这种队列叫双端队列(Double Ended Queue),学名Deque。
  • Stack
  • Iterator:使用迭代器的好处在于,调用方总是以统一的方式遍历各种集合类型,而不必关心它们内部的存储结构。
  • collections:Collections是JDK提供的工具类,同样位于java.util包中。它提供了一系列静态方法,能更方便地操作各种集合。

I/O

文件处理(练练编程就可掌握)

时间与日期

单元测试

  • Junit测试:单元测试可以确保单个方法按照正确预期运行,如果修改了某个方法的代码,只需确保其对应的单元测试通过,即可认为改动正确。此外,测试代码本身就可以作为示例代码,用来演示如何调用该方法。
  • fixTure:JUnit提供了编写测试前准备、测试后清理的固定代码,我们称之为Fixture。
  • 异常测试
  • 条件测试:@Disabled
  • 参数化测试

正则表达式

匹配规则、复杂匹配规则、分组匹配、非贪婪匹配、搜索和替换

安全和加密

  • 编码算法:
    • URL编码和Base64编码都是编码算法,它们不是加密算法;
    • URL编码的目的是把任意文本数据编码为%前缀表示的文本,便于浏览器和服务器处理;
    • Base64编码的目的是把任意二进制数据编码为文本,但编码后数据量会增加1/3。
  • 哈希算法:哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
    • 碰撞不可怕,我们担心的不是碰撞,而是碰撞的概率,因为碰撞概率的高低关系到哈希算法的安全性。一个安全的哈希算法必须满足
    • 哈希算法的另一个重要用途是存储用户口令。如果直接将用户的原始口令存放到数据库中,会产生极大的安全风险:
      • 数据库管理员能够看到用户明文口令;
      • 数据库数据一旦泄漏,黑客即可获取用户明文口令。
  • BouncyCastle:BouncyCastle就是一个提供了很多哈希算法和加密算法的第三方库。
  • Hmac算法:Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
  • 对称加密算法:对称加密算法就是传统的用一个密码进行加密和解密。例如,我们常用的WinZIP和WinRAR对压缩包的加密和解密,就是使用对称加密算法
  • 口令加密算法、密钥交换算法、非对称加密算法、签名算法(公知于大众)、数字证书(一层一层检验)

多线程(参考OS)

maven基础

  • 常用maven phase:经常用到的phase其实只有几个:
    clean:清理
    compile:编译
    test:运行测试
    package:打包
    • 执行一个phase又会触发一个或多个goal:

      执行的phase对应的goal
      compilecompiler:compile
      testcompiler:testCompile
      ^surefire:test
  • 使用插件:
    • 插件
      插件名称对应执行的phase
      cleanclean
      compilercompile
      surefiretest
      jarpackage
    • 自定义插件:定义plugin/configuration。
  • 多模块管理:中央仓库 私有仓库 本地仓库
  • munw:mvnw是Maven Wrapper的缩写。因为我们安装Maven时,默认情况下,系统所有项目都会使用全局安装的这个Maven版本。但是,对于某些项目来说,它可能必须使用某个特定的Maven版本,这个时候,就可以使用Maven Wrapper,它可以负责给这个特定的项目安装指定版本的Maven,而其他项目不受影响。简单地说,Maven Wrapper就是给一个项目提供一个独立的,指定版本的Maven给它使用。
  • 发布Artifact:
    • 可以发布到本地,然后推送到远程Git库,由静态服务器提供基于网页的repo服务,使用方必须声明repo地址;
    • 可以发布到central.sonatype.org,并自动同步到Maven中央仓库,需要前期申请账号以及本地配置;
    • 可以发布到GitHub Packages作为私有仓库使用,必须提供Token以及正确的权限才能发布和使用。

Gradle基础

Gradle使用教程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古剑诛仙

你的鼓励是我创造的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值