第三次实验室周报

知识梳理

  1. 模板方法设计模式:当子类有一部分相同的操作,也有不同的操作时,为了解决代码的复用性,就可以使用模板设计方法。模板设计方法提供了大体骨架,只有一个或多个方法待子类实现。
abstract class a{
    public long GetTotalTime{
           long begin = System.currentTimeMillis();
           doWork();
           long end = System.currentTimeMillis();
           return end-begin;
    }
    abstract public void dowork();
}
class b extends a{
     void doWork(){
             int sum=0;
             for( i=0;i<100;i++){
                   sum+=i;
             }
     }
}
class c extends a{
     void doWork(){
             int sum=0;
             for( i=0;i<10000;i++){
                   sum+=i;
             }
     }
}

通过类似方法可以节省很多代码来实现相应的功能。

2.接口:接口属于一种操作规范。接口是一种抽象类中的抽象类接口命名:有人习惯使用able/handle做后缀,为了区分是接口还是类,习惯使用I(大写i)作为接口前缀。
1)静态全局常量:接口中定义的变量,默认以 public static final修饰。
2)公共静态内部类:默认以public static修饰。
3)公共抽象方法:在接口中定义的方法,默认以public abstract修饰(只定义,不实现)。
4) java8允许在接口中使用默认方法和静态方法。
接口类特点:
1)没有构造方法,不能实例化。
2)接口只能继承接口,不能继承类,且接口支持多继承。
一个接口允许有多个父接口(例如:interface Iwalkable extends 接口1,接口2){}
3)接口里的方法全是抽象的,默认是public abstract。
4) 接口里的字段全是全局静态常量,默认修饰符public abstract final。
5)接口里的内部类全是静态的,默认修饰符public static。
四种内部类:
1)非静态内部类:内部类没有使用static修饰。
2)静态内部类(少用):内部类使用static 修饰。
3)局部内部类(少用):在方法中定义,会破坏封装。
4)匿名内部类适合于仅使用一次的类。
java8之前,匿名内部类只能访问final修饰的局部变量
若不使用final修饰,就会随着方法的结束而释放空间,但是类还存在(等待GC回收),则会报错。
接口的好处就是多态的好处。

class aNimal{
    void eat(){
        System.out.println("吃饭");
    }
    void sleep(){
        System.out.println("睡觉");
    }
}
interface Iwalkable{
    void walk();
    void eat();
}
interface Iswimable{
    void swim();
    void eat();
}
interface amphibian extends Iwalkable,Iswimable{         //两栖动物(接口多继承)

}
class cat extends aNimal implements Iwalkable{         //(实现类与接口的关系为实现关系)实现类也可以继承类,但是要写在implements之前
       public void walk(){
           System.out.println("走猫步");
       }
       public void eat(){
           System.out.println("吃皇粮");
       }
}
class dog extends aNimal implements Iswimable{
       public void swim(){
           System.out.println("狗刨式");
       }
       public void eat(){
           System.out.println("吃狗粮");
       }
}
class Frog extends aNimal implements amphibian {
       public void walk(){
           System.out.println("蛙步");
       }
       public void swim(){
           System.out.println("蛙泳");
       }
       public void eat() {
           System.out.println("无所不吃");
       }
}
public class Interface {
        public static void main(String[] args){
            Iwalkable cats=new cat();//运用到了多态
            Iswimable dogs=new dog();
            amphibian frog=new Frog();
            cats.walk();
            cats.eat();
            dogs.swim();
            dogs.eat();
            frog.walk();
            frog.eat();
            tests.show(new Iwalkable(){//使用匿名内部类(只是用一次对象)
               public void walk(){
                   System.out.println("狗狗步");
               }
               public void eat(){}
            });
        }  
}

接口和抽象类的区别(浅显理解):抽象类是对部分方法方法使用abstract, 然后让子类根据差异需求去实现抽象方法。而接口是对全部方法都使用abstract,以此来提供一种规范。在构造器方面:抽象类仍保留构造器,而接口没有构造器,也就是说不能创建对象。

3.枚举 :枚举和类一样,都有自己的属性、方法、构造方法,不同点是:枚举的构造方法只能是private修饰,也就无法从外部构造对象。构造方法只在构造枚举值时调用。

class Weekday{       //  近似于底层操作
    private Weekday(){}
    public static final Weekday MONDAY=new Weekday();
    public static final Weekday TUESDAY=new Weekday();
    public static final Weekday WEDNESDAY=new Weekday();
    public static final Weekday THURSDAY=new Weekday();
    public static final Weekday FRIDAY=new Weekday();
    public static final Weekday SATURDAY=new Weekday();
    public static final Weekday SUNDAY=new Weekday();
}
//等价于
enum Weekdays{
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}

关于枚举的一些操作:

public class Enum {
    public static void main(String[] args){
        //获取枚举类型的所有对象常量
        Weekdays[] days=Weekdays.values();
        System.out.println(days.length);
        
        //把一个字符串转化为一个枚举的常量对象
        Weekdays day=Weekdays.valueOf("MONDAY");
        System.out.println(day);
        
        //获取名称和序号
        System.out.println(day.name());
        //也可以
        String names=Weekdays.MONDAY.name();
        System.out.println(day.ordinal());
        int num=Weekdays.MONDAY.ordinal();
    }
}

4.组合关系概述: 从严格上说,继承关系不是用来解决代码复用的(破坏封装)。
这个时候,组合的好处就出来了,即在想要此功能的类中创建拥有该功能的对象,然后调用其方法。

5.字符串专题:字符串实际上就是一个字符数组。
字符串的分类:
1)不可变的字符串: String 类
2)可变的字符串: StringBuilder/StringBuffer类

String类:就表示不可变的字符串,一个String 对象只能表示一个固定的字符串,若内容改变,则对象也改变------------>所以String不擅长拼接(耗时长)。

针对这个问题:就要使用可变字符串(拼接不改变对象)StringBuilder / StringBuffer:
区别:
StringBuffer : 线程安全性较高,性能较低----------------------------->多线程使用StringBuffer
StringBuilder: 线程安全性较低,性能较高----------------------------->单线程使用StringBuilder

String对象的创建:
1)直接赋字面量: String name = “…”;----------------------------->会创建0 / 1 个对象,若存在,直接在常量池引用;不存在,就new一个。
2)使用构造器创建 String name = new String("…");---------------->会创建1 / 2 个对象,new一定创建了一个,另一个看常量池是否存在(在堆中开辟空间,然后引用常量池)。

String对象的空值:
1)引用为空: String name = null; 在内存中没有开辟/引用空间
2)空字符 : String name = " " ; 在内存开辟空间,只是没有内容数据
开发中经常判断非空的字符串:
public static boolean hasLength(String str){
TODO
}

值得记在小本本上的string面试题(不考虑常量池已经拥有):
String str1=“ABCD”;------------------------------------ 1 个
String str2=“A” + “B” + “C” + “D”;-------------------- 1 个 :编译器优化后,该代码等价于str1
String str3=“AB” + “CD”;------------------------------- 同上
String c =“CD”; String str4 = “AB” + c;------------- 不确定c是什么,需要在堆中开辟空间
String str5 = “AB” + get(); [get()方法返回"CD"]---- 同上

字符串的操作

public class StringDemo {
    public static void main(String[] args){
        String name="djas";
        char a=name.charAt(0); //返回字符串的索引对应的字符
        System.out.println(a);
        
        //是否以指定字符串为开头或结尾(true / false)
        String name1="abcdefg";
        System.out.println(name1.startsWith("ab"));
        System.out.println(name1.endsWith("fg"));
       
        //比较两个字符串
        String name2="abcdefg";
        System.out.println(name1==name2); // 比地址是否相同
        System.out.println(name1.equals(name2)); // 比内容是否相同
        //忽略大小写的比较内用(常用在验证码上);
        name2="ABCDEFg";
        System.out.println(name1.equalsIgnoreCase(name2));
        
        //String----------->byte[](用在存储二进制)
        byte[] data="ABCD".getBytes();
        //byte[]----------->String
        String str=new String(data);//通过构造器来转换类型
        System.out.println(str);
       
        //找出该字符串第一次 / 最后一次出现的位置
        String name3="aabbab";
        System.out.println(name3.indexOf("a"));
        System.out.println(name3.lastIndexOf("a"));
        
        //判断字符串是否为空
        System.out.println("".isEmpty());//实质上是判断长度为0
        name3=null;
        //System.out.println(name3.isEmpty());//实质上会抛出空指针异常
    
        //替换字符
        System.out.println("abacad".replace("a","o"));
       
        // 分割字符串: 比如想要提取字符
        name3="txt;doc;jpg;gif;pdf";
        String[] str1=name3.split(";");
        for(String ret:str1) {
            System.out.println(ret);
        }
        
        //判断一个文件名是何种类型(采取截断)
        String filename="1.2.3.gif";
        int last=filename.lastIndexOf(".");
        System.out.println(filename.substring(last+1));
        
        //转换大小写
        str="abSoSd";
        System.out.println(str.toUpperCase());
        System.out.println(str.toLowerCase());
        
        //把别的类型改为String类型
        String age=String.valueOf(17);
        //等价于
        String age1=17+"";
        System.out.println(age+"    "+age1);
       
        //trim: 消除字符串的前后空格(中间空格不能消)
        System.out.println(" abc ".trim());
        System.out.println(" abc ".length());
        System.out.println(" abc ".trim().length());
        
        //StringBuilder str=new StringBuilder();初始化长度默认为16
        //StringBuilder str=new StringBuilder(20);初始化长度为20
        StringBuilder name4=new StringBuilder("ABC");// 初始长度为:"ABC".length()+16
        System.out.println(name4);
        name4.append("略略略");
        System.out.println(name4);
        
        name4.deleteCharAt(4);//删除指定位置的字符
        System.out.println(name4);
        name4.reverse();//逆置字符串
        System.out.println(name4);
    }
}
  1. 和系统相关的类

java.lang.System:系统,封装系统相关的操作。不能被实例化。
Runtime: 运行时,封装运行时相关的操作。

举例相关方法:

通过类名访问:
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);----------数组拷贝
System.currentTimeMillis();--------------------记录当前时间,通常调用两次求差来计算程序运行时间
System.exit(0);---------------------------JVM退出
System.gc();------------------------------强制启动垃圾回收器

通过对象访问:
Runtime runtime=new Runtime();
runtime.exec(“notepad”);--------------------------新建一个记事本
7. Math类及其拓展
Math包封装了一系列与数学计算相关的类。
System.out.println(Math.E);---------------------自然对数e的值
System.out.println(Math.PI);--------------------π的值
System.out.println(Math.min(10,11)); --------最小值

double num = Math.random();----------------随机获取[0.0 ,1.0)之间的小数,伪随机数:通过一定 的算法,随机数也可以相等。
//获取 0–100的随机数
System.out.println( (int) (num100) );
//获取23–157之间的随机数
//23 + [0 , 134)
System.out.println( (int) (num
134+23) );

Rundom:此类实例用来生成伪随机数。
ThreadLocalRandom类:是Random类的子类,提供了更安全的随机数获取方式。

public class RandomDome {
    public static void main(String[] args){
        //获取[0 , 100)之间的随机数;
        //创建随机对象,使用对象访问方法
        Random random=new Random();
        int num=random.nextInt(100);
        System.out.println(num);
        //23--157
        System.out.println(23+random.nextInt(134));
        //升级版
        ThreadLocalRandom tlr= ThreadLocalRandom.current();
        num=tlr.nextInt(23,157);
        System.out.println(num);
    }
}

观察结果:
往往发现某个类中有很多非static的方法------>必须使用对象调用
但是。该类却没有向外暴露可访问的构造器----->使用者不能创建该对象
此时,该类通常会提供一个static方法,用于返回当前类的对象(单例设计)

UUID类:生成通用唯一的随机字符串。

public class UUIDdemo {
    public static void main(String[] args){
        //static UUID randomUUID : 生成随机的UUID值
        String uuid1= UUID.randomUUID().toString();
        //String uuid2= UUID.randomUUID().toString();-------------------将生成的随机验证码转化为字符串形式
        System.out.println(uuid1);
        //System.out.println(uuid2);
        String code=uuid1.substring(0,5).toUpperCase();--------------------------------生成5位随机验证码
        System.out.println(code);
    }
}

BigInteger和BigDecimal类:
BigInteger : 大整型,可以表示和接收任意范围的整数。
BigDecimal : 可以表示任意精度的小数,经常用于表示金额。

new BigDecimal(double val);把一个double值封装成BigDecimal对象因为往往你传入的值不会将double精度表示完整,导致最后的结果不精确所以可以使用字符串传入:new BigDecimal(String val)解决;

     		BigDecimal Num1=new BigDecimal(1.23456789);
            BigDecimal Num2=new BigDecimal(0.0001);
            BigDecimal ret=Num1.multiply(Num2);
            System.out.println(ret);
         	解决如下:
            BigDecimal Num3=new BigDecimal("1.23456789");
            BigDecimal Num4=new BigDecimal("0.0001");
            ret=Num3.multiply(Num4);
            System.out.println(ret);
  1. Error和Exception:
    Error指JVM退出,程序员无法处理。Exception指在编译时出错,程序员是可以避免的。他们有共同的父类:Throwable。

格式:
try{ (单个异常)
编写可能出现异常的代码
}catch(异常的类型 变量){
处理异常
}

try{ (多个异常)
编写可能出现异常的代码
}catch(异常的类型 变量){
处理异常
}catch(异常的类型 变量){
处理异常
}…

try{ (多个异常)
编写可能出现异常的代码
}catch(异常的类型 变量){
处理异常
}catch(异常的类型 变量){
处理异常
} finally{---------------------无论怎样,在程序最后一步都会执行

}

throw和throws:
throw:当某一个方法内部,在错误的时候,不知道返回一个什么值,
此时我们就使用throw返回一个异常对象,把异常对象返回给该方法的调用者。
throws:当一个方法,自身不处理异常,而是要把异常交给该方法的调用者处理,(抛出)
此时使用throws在该方法上表明自己不需要处理的异常(告诉调用者你需要处理什么异常)。

public class ThrowDemo {
        public static void main(String[] args){
           int num1=1;
           int num2=0;
           //两种方法解决------------------------------可以将异常用throws抛给调用者,或者直接捕捉异常(try--catch)
            try {
                int ret = divide(num1, num2);
                System.out.println(ret);
            }catch(Exception e){
                //获取错误原因
                System.out.println(e.getMessage());
            }
        }
        private static int divide(int num1,int num2){
            if(num2==0){
                throw new ArithmeticException ("除数不能为0");
            }
            int c=num1/num2;
            return c;
        }
}

Exception分为两大类:
1)编译时期异常:Checked:Exception类的子类,除了运行时期异常,其他的都是编译时期异常。
2)运行时期异常:Runtime:RuntimeException类和RuntimeException类的子类。
编译时期异常:要求必须处理,不处理,则报错。
运行时期异常:可处理,可不处理

你可能感兴趣的:(java)