• Java基础笔记


    Java笔记

    工作流程

    image-20200927105038121

    数据类型

    1. boolean 包含true或者false(默认值false)(注意:java中boolean的true和false与整数值1和0不等价,不可进行关系比较)
    2. 整数(默认值0)
      • byte 占一个字节,存储有符号整数-128~127,默认值0
      • short 两个字节,-32768~32767(-215 ~ 215 -1),默认值0
      • int 四个字节,约 -2x109 ~ 2x109 (-2^31 ~ 231 -1),默认值0
      • long 八个字节,约 -9x1018 ~ 9x1018 (-263 ~ 263 -1),默认值0L,整数表示在后面加L,如 0L
    3. 浮点型(不能表示很精确的数)
      • float 4字节,默认值0.0f。数量级1038 。数值表示时后面必须加f,如1.12f。
      • double 8字节,默认值0.0d。数量级10308 。数值表示时末尾d可省略
    4. char 字符型,占2字节,默认值'\u0000',用unicode编码表示,范围\u0000~\uffff。用单引号+字符/unicode码 表示,如 '我'、'\u4e00'
    5. 类成员变量有默认值,而函数成员变量是没有默认值的,需要初始化才可使用,否则报错。(所有变量定义时最好都初始化)

    分支和循环语句(与C++基本相同)

    1. 分支语句
      • if-else语句
      • switch-case语句(注意:Java中支持case为字符串)
    2. 循环
      • while
      • do-while
      • for循环
      • for-each

    函数定义

    1. 只能在类内定义
    2. 一般声明为public,方便外部访问
    3. 函数重载:函数名相同,函数参数表类型、参数数量不同
    4. main函数不是类的成员函数,而是程序入口,不能被其他函数调用(结构PSVM -- public static void main)

    命名传统

    1. main函数所在的类名和文件名相同
    2. 类名每个单词首字母大写 → 大驼峰法
    3. 方法和变量名首字母小写,其余单词首字母大写 → 小驼峰法
    4. 常量 (public static final) 一般全字符大写,单词中间以下划线相连

    面向对象

    简介

    1. 对象 = 属性 + 方法, 对象规范(类) = 属性定义 + 方法定义
    2. 变量的发展:基本类型(一种变量,可继承)⇒ 结构体(多变量捆绑,可包含但无法控制粒度)⇒ 类(变量 + 方法,可继承非private成员)
    3. 由面向过程 OP ⇒ 面向对象OO:OP注重行为的执行,变量是被动地被使用;OO更加注重行为的主体和类的重用
    4. 基本类型赋值是拷贝赋值,对象赋值是reference赋值
    5. 类成员变量有默认值,而函数成员变量是没有默认值的,需要初始化才可使用,否则报错。(所有变量定义时最好都初始化)

    构造函数

    1. 构造函数名和类名相同,且没有返回值
    2. 每个类必须有构造函数,如不定义,java自动生成一个无参构造函数;若定义构造函数,则java不会自动生成
    3. 每个变量都有生命周期,其生命周期包含在离它最近的{}内
    4. Java没有析构函数。这是因为Java提供内存自动回收机制,当变量退出其生命周期,JVM自动回收变量的内存。对象回收效率取决于JVM中的垃圾回收器GC(Garbage Collector)
    5. 每个子类的构造函数第一句话,都默认调用父类的无参构造函数super(),除非子类第一句话是super,且super语句必须放在第一条。不会连续出现两条super语句。

    信息隐藏

    1. 信息隐藏原则:类的成员属性是private,类的方法是public,其他类无法直接访问private属性,需通过public方法访问
    2. get和set方法是public,称为getter和setter方法。成员属性只能通过get和set访问。可通过IDE自动生成

    this指针

    1. 指代本类。 可访问类属性和方法,当不产生混淆时,可省略this(默认形参名称优先级高于成员变量)
    2. 可用于指代本类的构造函数

    继承

    1. 子类/派生类(Child/Derived Class)、父类/基类/超类(Father/Base/Super Class)
    2. 子类继承(extends)父类(包括父类的父类,依次类推)所有的属性和方法(但不能直接访问父类的private成员)
    3. 当子类存在和父类同名的属性和方法时(称为重写/覆写/覆盖 override,非overload),子类的属性和方法优先级更高 → 优先调用子类属性/方法
    4. 每个子类的构造函数第一句话,都默认调用父类的无参构造函数super(),除非子类第一句话是super,且super语句必须放在第一条。不会连续出现两条super语句。
    5. Java只支持单根继承,不支持多继承(与C++继承最大的不同)
    6. Java所有的类都继承自java.lang.Object类,Object类里有toString、Equals、clone、hashCode、finalize、getClass等方法

    抽象类

    1. 完整的类:所有的方法都被实现(存在 { 方法体 } )
    2. 当一个类的方法没有被全部实现时,该类需要被定义为抽象类,需要对类和未实现的方法添加abstract声明
    3. 子类继承抽象类时,必须实现抽象类的所有方法。否则子类也成为抽象类(需加abstract)
    4. 抽象类也是类,仍遵循单根继承
    5. 抽象类不能被实例化(被new出来)
    6. 抽象类组成:
      • abstract声明
      • (可选)成员变量,个数不限
      • (可选)具体方法,方法有实现,个数不限
      • (可选)抽象方法,加abstract,个数不限
    public abstract class Shape{
        private int area;
        public abstract int calArea();
    }
    

    接口

    1. 所有的方法都没有实现的类称为接口,需要改成interface声明。接口不能被实例化(new出来)
    2. 接口不是类,或者说是一种特殊的类。子类可以同时实现(implements)多个接口。继承和实现可以同时。
    3. 继承(extends)必须写在实现(implements)之前
    4. 接口可以继承(extends)多个接口(父类逗号隔开),继承父类未实现的所有方法
    5. 类实现接口,就必须实现未实现的所有方法。否则,需声明为抽象类
    6. 接口内可以定义变量,但一般是常量
    // Animal.java
    public interface Animal {
    	public void move();
    	public void eat();
    }
    
    // LandAnimal.java
    public abstract class LandAnimal implements Animal{
    	public abstract void eat();
    	public void move() {
    		System.out.println("I can walk by feet.");
    	}
    }
    
    // ClimbTree.java
    public interface ClimbTree {
    	public void climb();
    }
    
    // Rabbit.java
    public class Rabbit extends LandAnimal implements ClimbTree{
    	public void eat() {
    		System.out.println("I can eat.");
    	}
    	public void climb() {
    		System.out.println("I can climb tree.");
    	}
    	public static void main(String args[]) {
    		/* ... */
    	}
    }
    

    抽象类和接口的对比

    抽象类 接口
    abstract interface
    可以有部分方法实现 方法均没有实现
    子类只能继承一个抽象类 子类可以实现多个接口,接口可以继承多个接口
    有构造函数 无构造函数
    有main,能运行 无main
    方法可为private和protected 方法均为public

    转型、多态和契约设计

    1. 类转型:子类可以类型转换为父类(由大变小,向上转型。因为子类继承了父类所有成员),但父类不能转型为子类(由小变大,向下转型),除非父类对象本身就是子类转型得到
    2. 多态:子类转型为父类后,调用普通方法时,依旧是调用子类方法
    3. 多态的作用
      • 以统一的接口来操纵某一类不同对象的动态行为
      • 对象之间的解耦
    4. 契约设计:类不会直接使用另一个类,而是采用接口的形式,外部可以“空投”这个接口下的任意子类对象(通过多态实现对象之间的解耦)
      • Java编程设计遵循契约设计
      • 契约:规范了对象应该包含的行为方法
      • 接口定义了方法名称、参数和返回值,规范了派生类的行为
      • 基于接口,利用转型和多态,不影响真正方法的调用,实现调用类和被调用类的解耦(decoupling)
    /* Animal.java */
    public interface Animal{
        public void eat();
        public void move();
    }
    /* Cat.java */
    public class Cat implements Animal{
        public void eat(){
            System.out.println("Cat eat.")j;
        }
        public void move(){
            System.out.println("Cat move.");
        }
    }
    /* Dog.java */
    public class Dog implements Animal{
        public void eat(){
            System.out.println("Dog eat.")j;
        }
        public void move(){
            System.out.println("Dog move.");
        }
    }
    /* AnimalTest.java */
    public class AnimalTest{
        public static void main(String args[]){
            Animal[] A = new Animal[4];
            A[0] = new Cat();
            A[1] = new Dog();
            A[2] = new Cat();
            A[3] = new Dog();
            for(int i=0; i<A.length; ++i) {
                A[i].move();
            }
            haveLunch(new Cat());
            haveLunch(new Dog());
            haveLunch(new Animal{ // 匿名类
                public void eat(){
                    System.out.println("Anonymous class eat.");
                }
                public void move(){
                    System.out.println("Anonymous class move.");
                }
            })
        }
        public static void haveLunch(Aniaml a){
            a.eat();
        }
    }
    /* 输出:
    Cat move.
    Dog move.
    Cat move.
    Dog move.
    Cat eat.
    Dog eat.
    Anonymous class eat.
    */
    

    static和final

    1. static可修饰变量、方法、类、匿名代码块

      • 修饰变量:变量依赖于类存在,而不依赖于对象示例。不必new出来即可通过类名访问变量。类的所有对象实例共用一个静态变量(内存中只有一份拷贝)
      • 修饰方法:静态方法也可通过类名直接引用。静态方法中不能使用非静态成员(变量/方法),可以使用静态成员(变量/方法)。而非静态方法可以调用静态成员
      • 修饰类(内部类):用的较少
      • 修饰匿名方法块:
        • 直接由花括号{}包围的代码块成员称为匿名代码块
        • 调用顺序:static块 → 普通匿名代码块 → 构造函数
        • 静态static匿名代码块只在第一次加载类时调用,而普通匿名代码块在每次实例化时都会调用
        • 不推荐使用匿名代码块,可将代码块封装成如init函数等,方便管理和调用
    2. final可以修饰类、变量、方法

      • 修饰类:则该类不能被继承
      • 修饰方法:则该方法不能被子类重写override
      • 修饰变量:
        • 基本变量:变量的值不能被改变(即常量)
        • 对象类型:不能修改其指针(但能修改对象内部的值)
    3. 常量设计

      • Java中没有constant关键字
      • 常量不可被修改 → final,内存中只有一份 → static,方便被访问 → public(即public static final)
      • 常量 (public static final) 一般全字符大写,单词中间以连字符相连
      • 接口中的成员变量默认为常量(public static final可缺省)
    4. 常量池

      • Java为基本类型的包装类(不包括Float和Double)和String类型建立了常量池,相同的值只存储一份,以节省内存空间

      • 范围:

        • Boolean → true/false
        • Character → 0~127(\u0000 ~ \u007f)
        • Byte/Short/Integer/Long → -128 ~ 127
        • Float和Double:没有缓存(常量池)
        • Java常量字符串都建立常量池缓存机制
      • 包装类和字符串创建方式

        • 常量(字面量)赋值创建,放在栈内存(将被常量化)
        • new对象创建,放在堆内存(不会常量化)
        • 因此两种创建方式创建的对象地址不同
      • 包装类比较

        • 基本类型和包装类比较、包装类之间进行算术运算,将对包装类自动拆箱
        • 对象比较,比较地址
      • 字符串比较

        • 编译器会优化确定的字符串常量加法并使用常量池缓存。但对于包含new对象、变量之类的不确定字符串,则不优化

          String a = "abc";
          String b = "a" + "b" + "c";
          String c = "a" + new String("bc");
          // a == b ? true
          // a == c ? false
          
    5. 不可变对象(Immutable Object)

      • 典型不可变对象:八种基本类型的包装类、String、BigInteger、BigDecimal等
      • 创建方式:
        • Immutable对象不可改变,要改变,需clone/new一个对象进行修改
        • 所有属性都是private和final
        • 类是final或所有方法为final(避免继承过程中被修改)
        • 类中包含mutable对象,那么返回拷贝需要深度clone
      • 优点
        • 只读,线程安全
        • 并发读,提高性能
        • 可以重复使用
      • 缺点:制造垃圾,浪费空间
      • Java字符串
        • String类是典型的不可变对象,字符串内容比较用equals方法,是否指向同一对象用 ==
        • String类的加法效率低,可利用可变对象StringBuffer/StringBuilder类及其拥有的append方法运算
          • StringBuffer 同步,线程安全,修改快速
          • StringBuilder 不同步,线程不安全,修改极快
          • 修改速度:StringBuilder > StringBuffer > String
    import java.util.Calendar;
    
    public class Test {
    
    	public static void main(String[] args) {
    		final int n = 50000;
    		
    		Calendar t1 = Calendar.getInstance();
    		String a = "";
    		for(int i=0;i<n;++i) {
    			a = a + i + ",";
    		}
    		System.out.println(Calendar.getInstance().getTimeInMillis()-t1.getTimeInMillis());
    		
    		Calendar t2 = Calendar.getInstance();
    		StringBuffer b = new StringBuffer();
    		for(int i=0;i<n;++i) {
    			b.append(i);
    			b.append(",");
    		}
    		System.out.println(Calendar.getInstance().getTimeInMillis()-t2.getTimeInMillis());
    		
    		Calendar t3 = Calendar.getInstance();
    		StringBuilder c = new StringBuilder();
    		for(int i=0;i<n;++i) {
    			c.append(i);
    			c.append(",");
    		}
    		System.out.println(Calendar.getInstance().getTimeInMillis()-t3.getTimeInMillis());
    	}
    }
    //2712
    //6
    //3
    

    单例模式

    1. 限定某一个类在整个程序运行中只能有一个实例对象在内存空间中(即一个类有且只有一个对象)
      • 采用static共享对象实例
      • 采用private构造函数,防止外界new操作
    public class Singleton {
    
    	private static Singleton obj = new Singleton();
    	private String content;
    	
    	private Singleton() {
    		content = "abc";
    	}
    	
    	public String getContent() {
    		return content;
    	}
    
    
    	public void setContent(String content) {
    		this.content = content;
    	}
    	
    	public static Singleton getInstance() {
    		return obj;
    	}
    	
    	public static void main(String[] args) {
    		Singleton obj1 = Singleton.getInstance();
    		Singleton obj2 = Singleton.getInstance();
    		System.out.println(obj1.getContent() + " " + obj2.getContent());
            //abc abc
            
    		obj1.setContent("def");
    		System.out.println(obj1.getContent() + " " + obj2.getContent()); //def def
    		System.out.println(obj1 == obj2); // true
    	}
    }
    

    java访问权限

    访问权限 同一个类 同一个包 不同包的子类 不同包的非子类
    private
    (default)
    protected
    public

    建议:成员属性都用private,成员方法都用public

    package、import、jar和classpath

    package管理

    1. Java支持多目录放置java文件,通过package/import/jar包/classpath等实现跨目录放置和调用java
    2. package类似于C++ 中的namespace,需在文件第一句话给出
    3. java文件要严格放置在声明的package目录下
    4. 包名尽量唯一。常用域名逆序作为包名,如package cn.edu.zju;

    import

    1. 若所有java文件都放在同一目录下,则可以不进行显示调用声明
    2. import时,必须采用全称引用(包名+类名,无后缀),程序正文可以用短名称
    3. import必须放在package之后,类定义之前。多个import的顺序无关
    4. 可用*来import目录下的所有类,如import A.B.* (不建议,容易导致同名程序混乱),但是不包括下面的子目录文件(即不能递归包含)

    jar

    1. 本质:一组class文件的压缩包(其实存放java文件也是可以的)
    2. 优点:
      • 只有一个文件,便于网络传输
      • 只包含class文件,有利于保护版权
      • 便于版本控制
    3. 可利用Eclipse等IDE工具或jar.exe 打包和导入jar文件

    classpath(命令行)

    1. 编译格式:javac -classpath ".;<路径1>;<路径n>" A/B/C.java → 文件全路径
    2. 运行格式:java -classpath ".;<路径1>;<路径n>" A.B.C → 类的全称
    3. 编译时,用javac,classpath包含这个类依赖的类所在路径(以及依赖的类再次依赖的其他类)
    4. 运行时,用java,classpath除了包含编译时的classpath外,还要包括本类所在路径
    5. windows中路径用分号 ; 分隔,linux中用冒号 : 分隔;若路径中不含空格,classpath两侧双引号可省略

    Java常用类

    1. Java中的类已达几千个,所以记住每个类是不现实的,只需记住几个常用的类。遇到其他的类可查询Java的API文档
    2. java -- Java核心包, javax -- Java扩展包

    数字相关类

    1. BigInteger → 存储任意精度的整数
      • 不能直接用算术符号运算,相应的,用add(n) subtract(n) multiply(n) divide(n) 运算, divideAndRemainder(n)返回数值,包含商和余数
      • max(n) min(n)返回最大值和最小值
      • equals(n)比较数值大小,compareTo(n) 返回比较结果±1或0
    2. BigDecimal → 存储任意精度的浮点数,最好用字符串构造(用浮点数构造存在误差)
      • 不能直接用算术符号运算,相应的,用add(n) subtract(n) multiply(n) divide(n, 保留位数) 运算, divideAndRemainder(n)返回数值,包含商和余数
      • max(n) min(n)返回最大值和最小值
      • equals(n)比较数值大小,compareTo(n) 返回比较结果±1或0
    3. Random类
      • nextInt() 返回随机int, nextInt(n) 返回[0, n) 之间的随机int, nextDouble() 返回[0, 1]之间的浮点数,nextLong等依此类推
      • ints(n, left, right).toArray() 返回包含给定范围[left, right) 范围内(若省略则为int范围内)的整数流,加上toArray()转换为数组
      • Math类中的Math.random()返回[0.0, 1.0] 之间的浮点数
    4. java.lang.Math类
      • abs、sin、cos、pow、round、floor、ceil、PI

    字符串类

    1. String类(牢记常用方法) -- 不可变类,调用方法不影响对象本身
    String a = "123;456;789;123 ";
    System.out.println(a.charAt(0)); // 返回第0个元素
    System.out.println(a.indexOf(";")); // 返回第一个;的位置
    System.out.println(a.concat(";000")); // 连接一个新字符串并返回,a不变
    System.out.println(a.contains("000")); // 判断a是否包含000
    System.out.println(a.endsWith("000")); // 判断a是否以000结尾,startsWith类推
    System.out.println(a.matches("[a-z]*")); //判断是否符合给定正则表达式
    System.out.println(a.equals("000")); // 判断是否等于000
    System.out.println(a.equalsIgnoreCase("000")); // 判断在忽略大小写情况下是否等于000
    System.out.println(a.compareTo("abc"); //比较字符串大小,返回0或正负值。而compareToIgnoreCase忽略大小写
    System.out.println(a.hashCode()); // 返回字符串hash值
    System.out.println(a.length()); // 返回a长度
    System.out.println(a.trim()); // 返回a去除前后空格后的字符串,a不变
    String[] b = a.split(";"); // 将a字符串按照;分割成数组
    for (int i = 0; i < b.length; i++) {
        System.out.println(b[i]);
    }
    
    System.out.println("===================");
    
    System.out.println(a.substring(2, 5)); // 截取a的第2个到第5个字符(不包括第5), a不变
    System.out.println(a.replace("1", "a")); // replace和replaceAll均替换所有符合的字符串
    System.out.println(a.replaceAll("1", "a")); // replaceAll第一个参数是正则表达式
    
    System.out.println("===================");
    
    String s1 = "12345?6789";
    String s2 = s1.replace("?", "a");
    String s3 = s1.replaceAll("[?]", "a");
    // 这里的[?] 才表示字符问号,这样才能正常替换。不然在正则中会有特殊的意义就会报异常
    System.out.println(s1.replaceAll("[\\d]", "a")); //将s1内所有数字替换为a并输出,s1的值未改变。
    
    1. StringBuffer/StringBuilder类,可变对象,方法与String基本相同,区别在同步
      • 额外的方法:append/delete/insert/replace/substring
      • length() 字符串实际大小,capacity() 字符串占用空间大小(capacity >= length)
      • trimToSize() 取出空隙,将字符串压缩到实际大小(使capacity等于length)
      • 若有大量append,预估大小,再调用相应构造函数,可以提升性能

    时间类

    1. java.util.Date类

      • 基本废弃,主要使用getTime() 获取自1970-01-01年开始的毫秒数
      • 可直接System.out.println(d) 输出
    2. Calendar类 -- 目前主要使用的类(线程不安全)

      • Calendar为抽象类,不能直接new。需通过Calendar.getInstance()获取类(实际上创建的是其子类GregorianCalendar类)
      • get(field) 获取指定时间域,field包括Calendar类内的静态常量,通过Calendar.name调用。常用的有YEAR MONTH(0~11), DAY_OF_MONTH(可用DATE代替), HOUR(12小时制) , HOUR_OF_DAY(24小时制), MINUTE, SECOND, DAY_OF_WEEK(星期,1~7,从星期日开始) 注意月份和星期的特殊性
      • set(field, value) 设置某个时间域的值。set(year, month, date)设置年月日
      • add(field, value) 遵照日期规则增减某个时间域的值
      • roll(field, value) 不遵照日期规则,仅增减某个时间域的值(在该时间域范围内循环,如10月1日中日期减一天变成10月31日)
      • getTime() 返回相应的Date对象
      • getTimeInMillis() 返回1970-01-01以来的毫秒数
    3. java.time包(java 8 新类,线程安全,遵循设计模式)

      • LocalDate类

        • now() 返回当前时间的LocalDate对象, now(ZoneId.of("Asia/Shanghai")) 可加时区
        • of(year, month, date) 返回指定时间的LocalDate对象(month建议用Month类的枚举成员替代,如Month.January)
        • ofEpochDay(day) 返回自纪元日1970-1-1开始后的day天的日期
        • ofYearDay(day) 返回给定年份第day天的日期
      • LocalTime类

        • now() 用法同LocalDate,可加时区
        • of(hour, minute, second, nanoSecond) 创建指定时间
        • ofSecondOfDay(n) 返回一天中的第n秒的时间
      • LocalDateTime类

        • now() 用法同LocalDate,可加时区

        • of(year, month, day, hour, minute, second) 创建指定时间

          of(LocalDate.now(), LocalTime()) 通过LocalDate和LocalTime创建

        • ofEpochSecond(second, nanoSecond, ZoneOffset) 创建自纪元日开始的第几秒的时间

    格式化相关类

    1. java.text包

      • NumberFormat 数字格式化,抽象类,通过getInstance()实例化出子类DecimalFormat。具体格式查java API文档

        DecimalFormat df1 = new DecimalFormat("0.##"); // 0代表不可省略,#代表可省就省
        System.out.println(df1.format(0.80)); // output: 0.8, 若输入0.006则输出为0.01
        df1 = new DecimalFormat("#,##0.00"); //每3为用逗号,分隔
        
      • MessageFormat 字符串类格式化

        • 支持模板(参数)和文本(值)对位输出
        • 支持变量自定义格式,如数字、日期等
        String message = "{0}{1}{2}{3}";
        Object[] array = new Object[]{"A","B","C","D"};  
        String value = MessageFormat.format(message, array);  
        System.out.println(value);  
        message = "oh, {0,number,#.##} is a good number";  
        array = new Object[]{13.1415};  
        
      • DateFormat 日期格式化,抽象类,利用getInstance()示例化出子类SimpleDateFormat

        • parse方法:将字符串格式化为日期Date对象
        • format方法:将日期格式化为字符串
        String strDate = "2008-10-19 10:11:30.345" ;  
        // 准备第一个模板,从字符串中提取出日期数字  
        String pat1 = "yyyy-MM-dd HH:mm:ss.SSS";  
        // 准备第二个模板,将提取后的日期数字变为指定的格式  
        String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒" ;  
        SimpleDateFormat sdf1 = new SimpleDateFormat(pat1); // 实例化模板对象 
        SimpleDateFormat sdf2 = new SimpleDateFormat(pat2); // 实例化模板对象  
        Date d = null;
        try{
            d = sdf1.parse(strDate) ; // 将给定的字符串中的日期提取出来  
        }catch(Exception e){  // 如果提供的字符串格式有错误,则进行异常处理 
            e.printStackTrace() ;   // 打印异常信息  
        }
        System.out.println(sdf2.format(d));// 将日期变为新的格式  
        
    2. java.time.format.DateFormatter 时间格式化(java8发布,线程安全。SimpleDateFormat线程不安全)

      • ofPattern 设定时间格式
      • parse 将字符串格式化为时间对象
      • format 将时间对象格式化为字符串
      //将字符串转化为时间
      String dateStr= "2016年10月25日";
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
      LocalDate date= LocalDate.parse(dateStr, formatter);
      System.out.println(date.getYear() + "-" + date.getMonthValue() + "-" + date.getDayOfMonth());
      
      System.out.println("==========================");
      
      //将日期转换为字符串输出
      LocalDateTime now = LocalDateTime.now();
      DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm:ss");
      String nowStr = now.format(format);
      System.out.println(nowStr);
      

    Java笔记2

    异常

    分类

    1. 分类1:

      • Throwable 所有错误的祖先
      • Error系统内部错误或资源耗尽,不管
      • Exception:程序有关异常,所有异常的父类
        • RuntimeException:程序自身错误(如除0, 空指针,数组越界)
        • 非RuntimeException: 外界相关错误(打开一个不存在的文件、加载不存在的类)

      image-20201011082349790

    2. Unchecked Exception:包括Error和RuntimeException的子类(编译器不会辅助检查,需要程序员自己管的)。Exception中不是RuntimeException的即为Unchecked Exception

      Checked Exception:非RutimeException(编译器辅助检查,如果没有处理会报错)

    异常处理

    1. try-catch-finally(书写顺序不可变)
      • try中包含可能出现错误的代码
      • catch可以有0到多个,从上到下依次匹配,所以小异常要写在前面,大异常写在后面
      • 当有一个catch匹配时,进入相应catch代码块,且仅会进入一个catch代码块
      • 发生异常后,代码块后续代码不再执行,catch处理异常后也不再返回抛出异常的地方
      • finally可以有0到1个。无论是否有异常,异常是否被捕捉,finally都会执行
      • catch和finally至少要有一个
      • 代码块中能够再包含try-catch-finally结构
    2. 抛出异常
      • 方法存在可能发生异常的语句,但不处理,可以添加throws声明异常
      • 调用带有checked Exception的方法,要么处理这些异常,要么再次向外throws异常,直到main函数为止
      • 如果一个方法被覆盖,则覆盖它的方法也需要抛出相同的异常或异常的子类(不能超过父类抛出的异常的范围,即如果父类抛出n个异常,子类重写的方法可以不抛出、抛出1~n个异常或对应异常的子类)
    3. 自定义异常
      • 继承自Exception则变成unchecked Exception,继承自RuntimeException则变成Checked Exception
      • 自定义重点在构造函数
        • 调用父类Exception的message构造函数
        • 可以自定义自己的成员变量
      • 在程序中采用throw主动抛出异常
  • 相关阅读:
    Mysql大量插入随机数据方法--存储过程
    Linux永久修改系统时间和时区方法
    python反转字符串(简单方法)及简单的文件操作示例
    sql怎么批量替换字段里的字符串的
    varchar和Nvarchar区别
    VS改大小写的快捷键
    SQL中PIVOT 行列转换
    [转]VS中展开和折叠代码
    Bootstrap 标签页(Tab)插件
    C# DataTable 和List之间相互转换的方法
  • 原文地址:https://www.cnblogs.com/DreamEagle/p/15900384.html
Copyright © 2020-2023  润新知