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);
}
}
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) (num134+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);
格式:
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类的子类。
编译时期异常:要求必须处理,不处理,则报错。
运行时期异常:可处理,可不处理