day15学习笔记

113 阅读10分钟

知识点一:异常

/**

* 异常 : 程序在运行时出现的非正常状况 . 异常会导致程序崩溃

异常的分类 :

* 1) 按照程度来分

* 1) Error 严重错误 .

* 2) Exception 一般问题 .

 

* 2) 按照处理方式来分

* 1) 受检异常 (checked) 在程序中 必须 接受检查和处理的异常 . 如果不处理编译错误 , 也称为 编译时异常

* Exception 及其子类 (RuntimeException 及其子类除外 )

* 2) 非受检异常 (unchecked) 在程序中 不是必须 接受检查和处理的异常 , 如果不处理不生编译错误 , 但是运行时仍会出问题 , 也称为 运行时异常

Error 及其子类------非受检异常

RuntimeException 及其子类-------非受检异常 .

 

异常必须处理 : 适用于所有异常 , 包括 Error

*1) *捕获-------try catch结构

* try {

* 可能抛出异常的语句 ;

* } catch ( 可能的异常类型 1 引用 ) {

* 对异常处理 .

* } catch ( 可能的异常类型 2 引用 ) {

* 对异常处理 .

* } .....

* catch (Exception e) {

* 确保万无一失

* } finally { // final 修饰符 , 修饰类 , 方法 , 变量

无论前面try,catch发生什么都要执行。

通常在这里释放资源的操作。不在 GC 区中资源 , 而是由 OS 管理的资源 . 比如文件 , 网络等硬件资源 .

* }

组合(三种):

* try catch

* try catch finally

* try finally

 

*2) *抛出 *: *使用 throws 体现异常的抛出 .----核心是throws,最好要配合使用throw,表示诚实。

 

在方法签名中使用 throws 异常类型列表 , 作用是警告调用者 *, *此方法有风险 .

在方法体中使用 throw 语句 , 在方法中真的抛出异常对象 .

 

* 可以只有 throws 而没有 throw

* 只要有 throw 必须要有 throws

*

* throws 是警告,往上抛。不是真正的处理。

* throw 是玩真的 . 只有这个方法,才是真正的处理。

 

** 3) *先捕获 *, *再抛出 . ----本质上抛出了两个异常

*

* try {

* 可能抛出异常的语句 ;

* } catch(某个 任意异常类型 引用 ) {

* throw new 自定义异常 ( 引用 );-----已知异常对象作为实参。对象关联。

* }

 

处理方式的选择 : (如果出现了异常,是破坏了谁)

* 1) 入口方法尽量 捕获 . (栈底的方法出现问题是会影响大局的,栈一旦空,这个程序就 over 了。所以影响栈生死存亡的方法不能抛,要及时处理)

* 2) 功能方法尽量 抛出 .--->抛出异常实质上是一个消息反馈机制。 (把出错问题暴露出来,让调用者及时知晓,避免整体程序最后程序出错)

 

方法覆盖条件中对于异常的描述 : 一旦是非受检异常,就不受任何约束,他都不用检查的

* 要求如下 :

* 1) 方法签名一致 , 子类方法的返回值的对象类型 可以小于等于 父类方法返回的对象类型 .

* 2) 子类方法的访问控制修饰符的范围要 大于等于 父类的 .

* 3) 被覆盖方法不可以被 private, static(隶属于类), final.

* 4) 子类方法抛出的 受检异常范围要小于等于 父类方法抛出的受检异常 .--> 其实就是多态的时候,调方法是以父类为准,父类抛的异常小写,但是实际抛的确实子类的大的异常。那么 catch 就处理不了。

*/

 


// 自定义异常类 : 1) 继承Exception 表明它是一个异常, 2) 提供2个构造器一个String,一个是Throwable。 目的:创建自定义异常对象方便

 

 

class DividedByZeroException extends Exception { // 这是受检异常, 必须要处理

//构造器

    public DividedByZeroException(String message) {

        super(message); // 间接调用到父类构造, 完成私有的detailMessage的初始化.

    }

 //一个异常内部拥有另外一个异常对象

    public DividedByZeroException(Throwable cause) { // 对象关联专用,这个对象拥有另外一个对象作为属性,例如,我把电脑作为我的一个属性。 创建自定义类异常对象,传入了另外一个异常对象。

        super(cause);

    }

}

 

 

public class ExceptionTest {

    // 包装 : 自定义异常对象内部包含一个其他异常对象.

    public static int divide(int x, int y) throws DividedByZeroException {  //通过throws警告一下,警告谁呢?警告调用者

        try {

            return x / y;

        } catch (ArithmeticException e) {  //一下抓住这个ArithmeticException异常对象,然后包装到DividedByZeroException这个对象里面去。再把这个DividedByZeroException给扔出来。

            throw new DividedByZeroException(e); //以这个ArithmeticException已知异常对象为参数

        }

    }

 

 

    public static void main(String[] args) {

        try {

            try {

                System.out.println(divide(10, 2));

                System.out.println(divide(10, 0));

            } catch (DividedByZeroException e) {

                System.out.println(e.getMessage());

            }

            System.out.println(divide(20, 5));  //这里就是调用者,调用20 和5

        } catch (DividedByZeroException e) {

            e.printStackTrace();

        } finally {

            System.out.println("finally");

        }

    }

}

 

 

class ExceptionTest3 {

    // 在方法处的throws的作用是警告调用者, 调用此方法有风险!!!

    public static int divide(int x, int y) throws DividedByZeroException { // throws和throw最好要一致, 显得诚实

        if (y == 0) {

            // 真的抛出一个异常对象, 当前方法就会提前弹栈返回结束, 并给调用者产生破坏.

            throw new DividedByZeroException("除数不可以为0错误!!!!"); //这里是调用构造器,传入message形参

        }

        return x / y;

    }

 

 

    //public static void main(String[] args) throws DividedByZeroException {  //main方法虽然可以抛出异常, 但是不要抛.抛出来,就被操作系统干掉了。整个程序就会强制关闭

    public static void main(String[] args) {

        try {

            System.out.println(divide(10, 2));

            System.out.println(divide(10, 0));

        } catch (DividedByZeroException e) {

            System.out.println(e.getMessage());

        }

 

 

        System.out.println("end");

    }

}

 

 

class ExceptionTest2 {

 

 

    public static int divide(int x, int y) {

        if (y == 0) {

            RuntimeException re = new RuntimeException("除数不可以为0"); // throw和return效果一样, 都是让方法返回的

            throw re;

            // return 是和平返回, throw 带有破坏性的返回.

        }

        return x / y;

    }

 

 

    public static void main(String[] args) {

        try {

            System.out.println(divide(10, 2));

            System.out.println(divide(10, 0));

        } catch (RuntimeException e) {

            System.out.println(e.getMessage());

        }

        System.out.println("end...");

    }

}

 

 

 

class ExceptionTest1 {

 

    public static void main(String[] args) {

        System.out.println("main begin");

 

 

        boolean b = true;

        if (b) {

            //return;

        }

 

 

        try {

            int n = Integer.parseInt(args[0]);

            System.out.println(n);

            return;

        } catch (ArrayIndexOutOfBoundsException e) {

            System.out.println(e);

        } catch (NumberFormatException e) {

            System.out.println(e.getMessage());

        } catch (Exception e) {

            System.out.println("其他可能的异常 : " + e);

        } finally {

            // 无论前面try catch中发生什么, 我都要执行....

            System.out.println("finally");

        }

 

 

        System.out.println("main end");

    }

}

 

 

 


知识点二:接口的代理模式

/**

接口的特点:让完全不同类型的对象统一起来 。接口就是对不同类型的对象的统一。

*

* 代理 : 把代理对象当成被代理对象来使用 .---> 也就是有两个对象,一个是代理,一个是被代理。自己(被代理对象) -- 律师(就是代理) --- 法官把律师当成我。

* 代理和被代理对象之间有一个桥梁,这个桥梁,就是接口。 ---> 接口的一个典型应用。

* 接口就是代表一个能力。

*

* 代理模式的场景 :

* 1 使用者无法直接创建被代理对象。通过代理对象来完成。例如:来上海租房子,自己不知道怎么做,就找房屋中介来帮助自己。因为中介有找房子的能力。

* 2 (最主要场景)对于被代理对象的方法有改进的需求 . 但是同时不能修改被代理类。无形中,通过代理类,把被代理类功能增强了。比如,我想用支付宝转账,房东只收现金,这怎么办,通过中介。

*

* @author zhouyanjun

* @create 2020-07-13 23:23

*/

//这是一个接口 ,表示有租到房子这个能力

interface HouseRent {

    void rent();

}

 

 

//房东具备这种能力

class FangDong implements HouseRent {

 

 

    @Override

    public void rent() {

        System.out.println("我有房子要出租");

    }

}

 

 

//链接也要实现接口,因为他也必须要具有租房的能力

class LianJia implements HouseRent {

    //内部关联了对象。这个对象拥有另外一个对象作为属性。

    private HouseRent fd = new FangDong(); //这个声明也可以是接口,能提供租房功能的对象。

 

 

    @Override

    public void rent() {

        //是链家在出租房子

        System.out.println("请交中介费5000,不然不给出租");

        fd.rent();//原始方法调用。这里是切面,体现AOP

        System.out.println("要及时交房租,不然你住不了。支持微信,支付宝");

    }

}

 

 

public class ProxyTest {

    public static void main(String[] args) {

        //我们就是main方法。用户只身一人在上海,不会租房。

        //用户只能new代理对象

        //接口的使用,降低了对对象的要求

        HouseRent zufang = new LianJia();//无论我new的是什么,我只在乎能否租到房

        zufang.rent();

    }

}

 

 

 


知识点三:String

/**

* @author zhouyanjun

* @create 2020-07-14 14:25

*/

 

import org.junit. Test ;

 

/**

* String : 内容不可改变的 Unicode 字符序列 , 对象一旦创建 , 内容不能改变 .

* 对于字符串的内容的任何修改都会产生新对象 .

* 字符串内部就是使用一个 char[] 来保存所有字符的 .

*

* Customer cu = new Cutomer();

* cu.setAge(20); // 内容可以改变的对象

* cu.setAge(50);

*

* 0 2 10 15 21 27 32 34

* String string = " abcAQQY 我喜欢你 , 你喜欢我吗 ? 我不喜欢你 zzz123 ";

*

* public int length(). string.length() => 35 获取字符串长度 ( 字符数 )

* public char charAt(int index) 获取指定下标位置处的字符 string.charAt(12) => ' ', string.charAt(18) => ' ';

* public char[] toCharArray() 获取内部的 char[]

* char result[] = new char[value.length]; // 创建一个新数组 , 容量和内部的 value 一样大 .

*

* for (int i = 0; i < value.length; i++) {

* result[i] = value[i];

* }

*

* System.arraycopy(value, 0, result, 0, value.length);

* // 第一个参数是源数组对象 , 第二个参数是源数组的开始下标 , 第三个参数是目标数组对象 , 第四个参数是目标数组的开始下标

* // 第五个参数是要复制的元素个数 .

* public boolean equals(Object anObject)

* public int compareTo(String anotherString)

* public int indexOf(String s)

* public int indexOf(String s ,int startpoint)

* public int lastIndexOf(String s)

* public int lastIndexOf(String s ,int startpoint)

* public boolean startsWith(String prefix)

* public boolean endsWith(String suffix)

* public String substring(int start,int end)

* public String substring(int startpoint)

* public String replace(char oldChar,char newChar)

* public String replaceAll(String old,String new)

* public String trim()

* public String concat(String str)

* public String toUpperCase()

* public String toLowerCase()

* public String[] split(String regex)

*/

 

 

 

 

 

public class StringTest {

 

// 练习 : 把字符串反转一下

@Test

public void exer13 () {

String string = " abcAQQY 我喜欢你 , 你喜欢我吗 ? 我不喜欢你 zzz123 " ;

char [] arr = string. toCharArray ();

for ( int i = 0 ; i < arr. length / 2 ; i++) {

// 首尾交换 , i length - 1 - i

char tmp = arr[i];

arr[i] = arr[arr. length - 1 - i];

arr[arr. length - 1 - i] = tmp;

}

String string2 = new String (arr);

System . out . println (string2);

}

 

@Test

public void exer12 () {

String string = " abcAQQY 我喜欢你 , 你喜欢我吗 ? 我不喜欢你 zzz123 " ;

String string2 = "" ;

for ( int i = 0 ; i < string. length (); i++) {

char ch = string. charAt (i);

string2 = ch + string2;

}

System . out . println (string2);

}

 

@Test

public void exer1 () {

String string = " abcAQQY 我喜欢你 , 你喜欢我吗 ? 我不喜欢你 zzz123 " ;

String string2 = "" ;

for ( int i = string. length () - 1 ; i >= 0 ; i--) {

char ch = string. charAt (i);

string2 += ch;

}

System . out . println (string2);

}

 

@Test

public void test5 () {

String string = " abcAQQY 我喜欢你 , 你喜欢我吗 ? 我不喜欢你 zzz123 " ;

System . out . println (string. length ());

System . out . println (string. charAt ( 13 ));

System . out . println (string. charAt ( 0 ));

System . out . println (string. charAt ( 32 ));

//System.out.println(string.charAt(500));

System . out . println ( "**************************" );

for ( int i = 0 ; i < string. length (); i++) {

char ch = string. charAt (i);

System . out . println (ch);

}

System . out . println ( "***************************" );

char [] chars = string. toCharArray ();

for ( int i = 0 ; i < chars. length ; i++) {

System . out . println (chars[i]);

}

}

 

@Test

public void test4 () {

char [] arr = {

'a' , '1' , 'q' , ' 我 ' , '3' , ' 好 ' , 'o' };

String s1 = new String (arr); // 制作一个副本

arr[ 1 ] = ' 大 ' ;

System . out . println (s1);

 

String s2 = new String (arr, 2 , 3 ); // 2 个参数是开始下标 , 3 个参数是长度

System . out . println (s2);

String s3 = new String (arr, 0 , arr. length );

System . out . println (s3);

}

 

@Test

public void test3 () {

String s1 = "atguigu" ;

String s2 = "java" ;

String s4 = "java" ;

String s3 = new String ( "java" );

System . out . println (s2 == s3);

System . out . println (s2 == s4);

System . out . println (s2. equals (s3));

 

String s5 = "atguigujava" ;

// 字符串拼接时 , 如果有变量参与 , 结果一定是新字符串对象 , 并且在堆 .

String s6 = (s1 + s2). intern (); // intern() 作用是把字符串塞入常量区中 , 如果常量区中已经有此对象了 , 则返回常量对象的地址 .

System . out . println (s5 == s6); // true

System . out . println (s5. equals (s6));

 

}

 

@Test

public void test2 () {

String s1 = new String ();

String s2 = "" ;

String s3 = null ;

 

System . out . println (s1 == s2);

System . out . println (s1. equals (s2));

 

String s4 = new String ( "qqq" );

 

 

}

 

@Test

public void test1 () {

String s1 = "abc" ;

s1 += "yyy" ;

System . out . println (s1);

}

}

 


 

作业一: