声明:学基础,在校学生,本文所有内容来自书本和视频,然后通过自己的理解和筛选编写而来,如有理解不到位的写得不到位的地方,欢迎评论指错!!!(仅做学习交流)
笔者:Fhvk
微信:WindowsC-
内部类
- 内部类:就是类中的类;
- 内部类访问的特点:
1,内部类可以直接访问外部类的成员,包括私有的;
2,外部类要访问内部类,就必须要创建对象; - 创建内部类对象:外商类名.内部类名 对象名 = new 外部类名().new 内部类名();
- 私有内部类
public class Outer {
private int num;
private class Inner {
public void method() {
System.out.println(num);
}
}
/*
可以把内部类当成一个私有的成员对象;
等同于num是私有的;
可以提拱公共对外访问方法;
*/
public void print() {
Inner i = new Inner();
i.method():
}
}
public class Demo_InnerClass {
public static void main(String[] agrs) {
//error 内部被私有不能创建对象
Outer.Inner oi = new Outer().new Inner();
}
}
- 静态内部类
public class Demo_InnerClass {
public static void main(String[] agrs) {
Outer.Inner oi = new Outer.Inner();
oi.method();
//如果内部类method方法也定义为static:Outer.Inner.method();
}
}
public class Outer {
static class Inner {
public void method() {
System.out.println("Hello World!");
}
}
}
- 局部内部类:类外部类中方法中出现的类,可以把局部内部当成一个局部变量,生命周期随着方法的存在而存在;所以只能在方法内进行创建对象;
- 匿名内部类
1,就是内部类的简化写法;
2,前提存在一个抽象类/接口/类;
3,格式:new 类名/抽象类名/接口 () {};
4,是继承一个类、接口、抽象类,并重写了所有的抽象方法的匿名的子类对象;
5,匿名内部类只针对重写一个方法使用;另外不能向下转型没有子类名;
6,匿名内部类当做参数使用;
class Demo_InnerClass {
public static void main(String[] agrs) {
Outer o = new Outer():
o.method();
}
}
class Outer {
interface Inner {
public abstract void print();
}
public void method() {
new Inner() {
public void print(){
System.out.println("你好呀!");
}
}.print();
}
}
java.long.Object类(超类)
- Object:所有类都直接或者间接的extends了该类;只有一个空参的构造方法;
- Object重要的方法
1.hashCode():该方法返回该对象的哈希码值(就是地址编号);注意是int数,用int接收;
2,getClass():该方法返回此对象的运行时类,而且可以通过Class类中的getName()方法获取该真实全类名;
例:Class clazz = 对象名.getClass();
String name = class.getName();
具体会在反射去讲
3,toString():可以更方便的显示属性值;返回的是String;直接重写该方法,不然没有意义;因为如果不重写,默认调用Object里的toString()方法;
Object中如何实现toString()
public String toString() {
return getClass().getName() + "@" + Intger.toHexString(hashCode());
// toHexString():将一个整数转化一个16进制的无符号字符串表现形式;
}
4,equals(Object obj):当前对象是否与传进来的对象相等;返回一个boolean;Object类中该方法比较的是地址值;没有意义;直接重写该方法,用于比较属姓;
//重写前Object类中
public boolean equals(Object obj) {
return (this == obj); //很明显比较的是地址值
}
//重写后 例如我在Studebt类(自定义类)中重写,属性有name,age;
public boolean equals(Object obj) {
//要想调用属性必须向下转型;因为接收的是 Object引用,属于多态,缺点就是不能使用子类特有的属性和行为
Student s = (Student)obj;
return this.name.equals(s.name) && this.age = s.age;
}
总结:==与equals()方法的区别
共同点: 都可以用来比较,返回都是true/false
不同点:==可以比较基本数据类型也可以比较引用数据类型;equals方法只能比较引用数据类型也就是比较地址;
java.util.Scanner(文本扫描器)
- Scanner:一个可以使用正则表达式来解析基本数据类型和字符串的简单文本扫描器;
- 该类构造:用得最多的是Scanner(InputStream source);IO流输入流
Scanner sc = new Scanner(System.in); /*标准的键盘输入流,用得构造是InputStream,只是饭装了而已;*/
int i = sc.nextInt();
- 两个常用方法
1,nextXXX():获取下一个输入项,XXX可以是Double、Int等,Scanner使用空格,回车作为分界符;
2,hasNextXXX():判断下一个输入项;
// 配合使用
Scanner sc = new Scanner(System.in);
if(hasNextInt()) {
int i = sc.nextInt();
}else {
System.out.println("输入类型有误!!!");
}
3,注意事项:nextInt()和nextLine()方法最好不要同时使用,原因:nextline()方法录入的是一行数据结束标记符是/r/n;
class Test {
public static void main(String[] agrs) {
Scanner sc = new Scanner(System.in);
int i = nextInt();
String s = nextLine();
System.out.println("i = " + i);
System.out.println("s = " + s);
}
}
很明显,s根本没有获取值,当我们输入1换行时,nextInt()把1拿走,其实还有/r/n所以,nextLine()遇到/r/n结束所以什么也没获取到;
解决方法:1,创建多个Scanner,浪费空间;2,全部使用nextLine(),然后通过后面学的知识将字符串整数转换为整数(用第2种)
java.long.String(字符串)
- String:代表字符串,Java程序中的所有字符串字面值都做为此类对象;如"abc"就是一个对象,可以用它调用"abc".equals(“abc”);所以不能被修改,字符串属于常量,修改的话属于地址修改;而不是把原来那个给修改,因为是对象;
- String常用构造:
1,空参构造:String();
2,有参构造:
byte[] arr1 = {97,98,99,100};
String str1 = new String(arr1);//将字节数组转换为字符串,通过平台字符码集解码;
String str2 = new String(arr1,0,2);//将从下标0开始转换2个字节为字符串;
char[] arr2 = {'a','b','c','d','e','f'};
String str3 = new String(arr2);//将字符数组转换为字符串;
String str4 = new String(arr2,0,2);//将从下标0开始转换2个字符为字符串;
//字符数组与字符串可以互相转换,通过toCharArray();接收的是字符数组;
- String判断功能(方法)
boolean equals(Object obj):String类重写了equals,比较的是字符串内容字符序列;相同true,否则false;区分大小写;
boolean equalsIgnoreCase(String str):比较字符串内容。不区分大小写;
boolean contains(String str):判断是否包含传入的字符串;
boolean startsWith(String str):判断是否以传入字符开头;
boolean endsWith(String str):判断是否以传入字符结尾;
boolean isEmpty():判断字符串内容是否为空;
注意:null和"“空字符的区别:”"是一个String对象有地址值,null是空常量不能调用任何方法,否则指针异常; - String获取功能(方法)
int length():获取字符串内容每一个字符的个数;
char chaAt(int index):获取指定索引位置的字符;
int indexOf(int ch):返回指定字符在此字符串中第一次出现的索引;如果不存在返回-1;
int indexOf(String str):返回指定字符在此字符串中第一次出现的索引;如果不存在返回-1;
int indexOf(int ch,int formIndex):返回指定字符在字符串中指定位置后第一次出来的索引;
int indexOf(String str, int formIndex):返回指定字符在字符串中指定位置后第一次出来的索引;
int lastIndexOf(int ch):从后向前找,第一次出现的位置;注意索引不变!
int lastIndexOf(int ch,int formIndex):指定开始位置向前找;
String substring(int start);指定位置开始获取字符,默认到未尾;
String substring(int start, int end);指定位置开始获取到指定位置结束;包含头不包含尾;
//遍历字符串
String str = "abcde";
for(int i = 0; i < str.length(); i++) {
Sysotem.out.println(str.charAt(i));
}
- String转换功能(方法)
byte[] getBytes():把字符串转换为字节数组;
char[] toCharArray():将字符串转换为字符数组;称为编码;
static String valueOf(char[] arr);将字符数组转换为字符串;底层用得也是String构造
static String valueOf(int i);将int数转换为字符串;重载的方法各种数据类型都可以转换
String toLowerCase();把字符串转换成小写;
String toUpperCase();把字符串转换成大写;
String concat(String str);把字符拼接;
+与concat的区别:+更强大,任意类型都可以与字符拼接,而concta只能与字符串拼接;
//第一个字符大写,之后所有字符小写
String s1 = "aasSBJSJSKLSSasbaxaSBj";
String s2 =
s1.substring(0,1).toUpperCase().concat(s1.substring(1).toLowerCase());
链式编程:只要保证每次调用返回的都是对象,就可以继续调用;
- String其它功能(方法)
String replace(char old,char new);将old字符,全部替换为new字符;如果不存在就不变;
String replace(String old,String new);将old字符串,全部替换为new字符串;如果不存在就不变;
String trim();去除字符串两端的空格;
int compareTo(String str);按照字典顺序比较,返回 负数 0 正数,三种情况
int compareIgnoreCase(String str);不区分大小写比较;
java.long.StringBuffer(缓冲区)
- StringBuffer:线程安全的可变字符序列;
- StringBuffer和String的区别:String是一个不可变的字符序列,而StringBuffer是一个可变的字符序列;
- StringBuffer构造:
//空参构造,初始大小为16
StringBuffer sb = new StringBuffer();
System.out.println(sb.llength()); //容器中的字符个数
System.out.println(sb.capacity()); //容器大小,初始大小为16;
//有参构造
StringBuffer sb = new StringBuffer(10); // 指定容器大小
StringBuffer sb = new StringBuffer("sabas"); //直接给定字符串,字符串大小 + 初始容量,所以大小为21。
- StringBuffer添加功能
public StringBuffer append(String str):追加的意思;可以把任意数据类型数据追加到字符串缓冲区,并返回组冲区this;就是同一个对象;
public StringBuffer append(int offset,String str):指定位置插入,返回StringBuffer,跟上面一样,重载的方法任意类型可以追加;
- StringBuffer删除功能
public StringBuffer deleteCharAt(int index);删除指定位置的字符,返回本身
public StringBuffer delete(int start,int end);删除从指定位置开始到结束位的字符(包含头不包含尾),返回本身;
注意:如果没有该索引,就会报字符串索引越界异常;
清空缓冲区:sb.delete(0,sb.length());
- StringBuffre替换和反转功能
public StringBuffer replace(int strat,int end,String str);替换功能,包含头不包含尾;
public StringBuffer reverse();字符串反转功能;
-
StringBuffer截取功能及注意事项
public String substring(int start);截取指定位置开始字符串
public String substring(int start, int end);包含头不包含尾
注意:StringBuffer中substring()方法返回的是字符串String而不是本身; -
StringBuffer与String之间的转换
String->StringBuffer
1,通过StringBuffer构造方法;
2,通过append()方法添加字符串;
StringBuffer->String
1,通过String构造方法;
2,通过toString()方法;
3,通过substring()方法; -
StringBuffer和StringBuilder的区别
看下面试题第4题 -
String与StringBuffer形式参数问题
String类虽然是引用数据类型,但是在做为参数传递的时候和基本类型一样;String是不可变的字符序列;如果修改是重新在常量池创建了一个字符串,地址肯定不一样;
java.util.Arrays
- 数组工具类:提供了很多方法对数组进行操作如果排序、查找等,工具类里面的方法全都是静态,可以类名点调用,构造也私有,不要别人new对象,没有意义就是一个工具,类名点调用就好;
- Arrays常用的方法
public static String toString(int[] a);用于数组转有格式的字符串;
public static void sort(int[] a);用于排序的方法 底层用的快排
public static int binarySearch(int[] a, int ley);用于查找数组元素,返回下标,如果该数不存在就返回负的插入点-1;注意查找前先对数组排序;因为该方法底层用得是二分查找法;
基本数据类型包装类
- 包装类的好处:将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
double | Double |
float | Float |
char | Character |
boolean | Boolean |
- 常用操作:用于基本数据类型与字符串之间的转换;
- Integer类的构造
Integer it = new Integer(int value);//将int数转成包装类对象
Integer it = new Integer(String str); //将数字字符串转成Integer对象
重要的常量值Integer.MAX_VALUE:代表int取值最大值. MIN_VALUE:int取值最小值
- String和int间的相互转换
int->String:
1,用"+"接接; //推荐用这种1
2,String类中有一个valueOf(int value); //推荐用这种2
3,Integer.toString(int value);
String->int:
1,通过Integer.parseInt(String str); //开发用这种; - 注意:8种基本数据类型包装类,其中七种都有parseXXX()方法,可以将这是七种的字符串表现形式转成基本数据类型;
//1,Boolean
String str = "true";
boolean b = Boolean.parseBoolean(str);
//2,Integer
String str = "1";
int i = Integer.parseInt(str);
//3,Float
String str = "1.1";
float f = Float.parseFloat(str);
//4,Double
String str = "2.1";
double d = Double.parseDouble(str);
//5,Byte
String str = "34";
byte b = Byte.parseByte(str);
//6.Long
String str = "453L";
long l = Long.parseLong(str);
//7.Short
String str = "34";
short s = Short.parseShort(str);
注意:只有七种,只有Character没有,因为字符串有多个字符,而char类型只能存一个字符所以没有该方法,解决方法:通过toCharArray()方法可以转换成char[];
- 自动拆箱与自动装箱
自动装箱:把基本数据类型转换为包装类;
自动拆箱:把基本数据类型包装类转换为基本数据类型
Integer i1 = 100; //自动装箱;
int i2 = i1 + 200; //自动拆箱;
注意:Integer i3 = null;就不能拆箱;原因;其实上面底层都是通过方法实现的而为null就不能调用方法,就会报空指针异常;
正则表达式(java.util.Regex)
- 作用:比如注册邮箱,邮箱有用户名和密码,会对其限制长度和规则,这个限制就是用正则表达式实现的;
- 字符类
1、[abc]:中括号代表单个字符,a、b、c的单个字符为true;
2、[^abc]:中括号代表单个字符,除a、b、c的所有的单个字符为true
3、[a-zA-Z]:中括号代表单个字符,a-z或A-Z范围内的单个字符为true;
4、[a-c[d-f]]:中括号代表单个字符,a-z与d-f范围内的单个字符为true;(并集)
5、[a-z&&[def]]:中括号代表单个字符,a-z中的d、e、f的单个字符为true(交集)
6、[a-z&&[^def]]:中括号代表单个字符,a-z中除 d、e、f的所有单个字符都为true;
7、[a-z&&[^m-p]]:中括号代表单个字符,a-z中除范围为m-p的所有单个字符都为true;
9、[0-9]:中括号代表单个字符,0-9范围的单个字符为true; - 预定义字符类
1、“.”:点代表任意字符的单个字符;
2、\\d:代表数字字符;[0-9];
3、\\D:代表非数字字符;[^0-9];非数字就是true
4、\\s:空白字符 [ \t\n\xOB\f\r];
5、\\S:非空白字符[^\s];
6、\\w:单词字符 [a-zA-Z_0-9]
7、\\W:非单词字符 [^\w] - 数量词
1、X?:字符数量一次或者一次也没有;
2、X*:字符数量零次或者多次(包含一次哈);
3、X+:字符数量一次或者多次(不包含零次);
4、X{n}:字符数量出现刚好n次;
5,X{n,}:字符数量出现至少次;
6、X{n,m}:字符数量出现最少n个,不超过m个; - 正则表达式的分割功能
功能:通过String类中split(String regex)方法获取下面姓名;通过正则表达式把、去除得到有用数据;
split()方法返回一个字符串数组,参数是要分割的正则表达式;
String s = "李超武、陈清香、侯冰、吴非凡、阳文杰";
String regex = "[、]";
String[] arr = s.split("、");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
运行后:李超武陈清香侯冰吴非凡阳文杰
注意:如果出现预定义字符要转义 例如 :出现点就"\\.";
- 正则表达式的替换功能
功能: 通过String类中的replaceAll(String regex,String replacement)方法将字符串s 中所有数字删除
String s = "asd237bh322";
String s2 = s.replaceAll("\\d","");
System.out.println(s2);
运行后:asbbh
- 正则表达式的分组功能
public class Demo5_regex {
public static void main(String[] agrs) {
System.out.println("高高兴兴".matches("(.)\\1(.)\\2"));
System.out.println("高兴高兴".matches("(..)\\1"));
}
}
demo1
demo2
注意:$1代表第一组的内容;
- Pattern类&Matcher类
1、compile(String regex):将给定的正则表在达式编译到模式中;
2、matcher(String str):创建匹配给定输入与此模式的匹配器;返回一个Matcher对象
3、matches():判断是否,true/false;
public class Test12 {
public static void main(String[] agrs) {
String str = "我的电话有13787848265,15074762880,18821873273";
Pattern p = Pattern.compile("1[3578]\\d{9}"); //获取得到正则表达式
Matcher m = p.matcher(str); //获取匹配器
while(m.find()) {
//find()查找该匹配模式中的下一个子序列、调用一次指针自动下移;
System.out.println(m.group()); //group()返回匹配的字符串
}
}
}
java.long.Math(数学相关类)
- 作用:类中包含用于执行基本数学运算的方法,如平方根、指数、对数、和三角函数等;
Math.PI:圆周率
Math.abs(int a):求绝对值;重载的方法
Math.ceil(double a):向上取整,返回的是一个double;
Math.floor(double a):向下取整,返回一个double;
Math.max(int a,int b):求两个数最大值;
Math.min(int a,int b):求两个数最小值;重载的方法
Math.pow(double a,double b);前面的数是底数,后面的数是指数,就是a的b次方;
Math.random();生成0.0~1.0间的数,不包括1.0;
Math.round(float a):四舍五入;返回int. ;重载的方法;
Math.sprt(int a):开平方
java.util.Random(伪随机数)
-
作用:此类用于产生随机数
-
构造方法:
Random():创建一个新的随机数生成器
Random(long a):使用单个long种子创建一个新的随机数生成器; -
nextInt(int n):生成0~n-1间的随机数(重点)
java.long.System
- System类包含一些有用的类字段和方法,它不能被实例;
- 成员方法
1、gc():运行垃圾回收器;这里要说到fianlize()该方法是Object中的,作用是当该对象变成垃圾时自动调用该方法回收,而gc()方法就是手动调用此方法,自动回收要达到一数量的垃圾才调用;
2、exit(int n):终止当前运行的java虚似机;参数0代表正常终止,非0异常终止;
3、currentTimeMillis():获取当前时间毫秒值;1970-01-01开始;
4、arraycopy(Object src, int srcPos,Object dest, int destPos,int length);复制数组;
int[] src = {1,2,3,4,5,6,7,8};
int[] dest = new int[8];
System.arraycopy(src,0,dest,0,src.length);//复制src数组从0开始的元素,到dest数组从0开始的位置,复制src元素个数的个数;
应用在:集合底层
java.math.BigInteger
- 作用:可以存比int更大的数
- 构造方法;
1、public BigInteger(String str); - 成员方法
1、public BigInteger add(BigInteger val);相加
2、public BigInteger subtract(BigInteger val);相减
3、public BigInteger multiply(BigInteger val);相乘;
4、public BigInteger divide(BigInteger val);相除;
5、public BigInteger[] divideAndRemainder(BigInteger val);相除(/)AND相模(%);
java.math.BigDecimal
- 作用:为了更精确的计算、表示浮点数
- 构造方法;
1、public BigDecimal(String val); 最好用这种字符串形式
2、public BigDecimal(double val); - 成员方法
1、public BigDecimal add(BigInteger val);相加
2、public BigDecimal subtract(BigDecimal val);相减
3、public BigDecimal multiply(BigDecimal val);相乘;
4、public BigDecimal divide(BigDecimal val);相除;
5、public BigDecimal[] divideAndRemainder(BigDecimal val);相除(/)AND相模(%);
6、静态方法BigDecimal.valueOf(double);将一个double转成一个BigDecimal对象
java.util. Date(日期类)
- Date:表示特点的瞬间,精确到毫秒;
- 构造方法
1、public Date();
2、public Date(long date);
注意:如果参数是0代表的是什么的1970-01-01 8:00:00
如果没有参数代表当前时间; - 成员方法
1、public long getTime():获得从来1970-01-01以来,由此对象表示的毫秒数;(还有一个个方法System.currenyTimeMillis()同样功能);
2、public void setTime(long time);设置由1970-01-01以来的毫秒数;
java.text.DateFormat&&java.text.SimpleDateFormat
- 它俩的关系:DateFormat是父类,SimpleDateFormat是子类(DateFormat是抽象类)
- 作用:格式化日期类;
- SimpleDateFormat的构造方法:
public SimpleDateFormat();
public SimpleDateFormat(String pattern); 用得最多
//空参构造
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.format(new Date()); //获取当前时间,format()是从父类继承下来的,返回一个Strinf;
//有参构造
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");//自定义格式
sdf.format(new Date()); //当前时间;
- 将时间字符串转换成一个日期对象
String str = "1999年10月18日 08:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d = sdf.parse(str); //本方法用于将字符串日期转成日期对象
- 经典:我来到这个世界多少天?
java.util.Calendar(日历类)
- Calendar:是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历的字段之间的转换提供了一些方法;
- 使用
Calendar c = Calendar.getInstance();//方法里面其实new的是子类,所以符合多态; - 成员方法
public int get(int field):根据字段返回指定信息;
例:System.out.println(Calendar.YEAR);//输出年,直接类名点调用,这种字段很多直接查API
注意:
1、Calendar.MONTH:月是从0开始数的;
2、Calendar.DAY_OF_WEEK:周日是第一天,周六是最后一天;
- 输出年月日星期
public void add(int field,int amunt):给指定字段 + -
public final void set(int year,int month,int date);设置年月日;
public final void set(Calendar.YEAR,2000);修改指定字段;重载的方法;
- 判断是否闰年
public class Test13 {
public static void main(String[] agrs) {
int year = 0;
Scanner sc = new Scanner(System.in);
System.out.println("请输入年份:");
if(sc.hasNextInt()) {
String line = sc.nextLine();
year = Integer.parseInt(line);
} else {
System.out.println("输入有误!!");
}
boolean b = getYear(year);
System.out.println(b);
}
public static boolean getYear(int year) {
if((year % 4 == 0 && year % 100 != 0)||(year % 400 == 0)) {
return true;
} else {
return false;
}
}
}
java.text.NumberFormat&&java.text.DecimalFormat
- NumberFormat作用:数字化格式类,是一个抽象类;
- 基本使用
import java.text.NumberFormat;
public static void main(String[] agrs) {
NumberFormat nf = NumberFormat.getInstance();//返回本地默认格式
System.out.println(nf.format(100000));
}
- DecimalFormat作用:是NumberFormat的子类,可以直接指定显示的模版;
- 基本使用
import java.text.DecimalFormat;
public class Demo2_DecimalFormat {
public static void main(String[] agrs) {
FormatDemo df = new FormatDemo();
df.format1("###,###.###元", 11122233.11323);
df.format1("000,000.###元", 1113.11323);
df.format1("##.###%", 0.233343);
df.format1("00.##%", 0.0231);
}
}
class FormatDemo {
public void format1(String pattern,double value) {
DecimalFormat df = new DecimalFormat(pattern);
System.out.println(df.format(value));
}
}
- 两者区别和使用
1、NumberFormat完成的功能只是根据区域不同固定的数字显示格式
2、DecimalFormat是可以由用户自己指定显示格式,所以比较好用,这也是子类的特点,子类比父类好用;
对象克隆技术(Objcet中clone&&Cloneable接口)
- 对象的克隆:完成复制一个对象;
- 使用:如果想要完成对象克隆,就必须使用到Object中clone()方法,并重写它把权限扩大,因为在Object中它的修饰符是protected,还要实现Clonable接口(标识接口,里面没有任何方法),才是一个可以被克隆的类
class Person implements Cloneable {
String name;
public Person(String naem) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String toString() {
return "姓名:" + name;
}
public Object clone() {
return super.clone();
}
}
class CloneDemo {
public static void main(String[] agrs) {
Person p1 = new Person("张三");
Person p2 = (Person)p1.clone(); //向下转型
p2.setName("李四");
System.out.println(p1);
System.out.println(p2);
}
}
总结:在以后的java类库中经常看到Cloneble接口的出现,一定要记住;只有实现了此接口对象才可以被克隆;
比较器(Comparable< T >,Comparator< T >)
- 为什么要有比较器?
1、Arrays中sort()方法,此方法可以直接对对象数组进行排序,但前提必须实现Comparator接口 并重写compareTo()用于指定排序规则;
2、compareTo()方法有三个返回值;大于返回1,小于返回-1,等于返回0;
import java.util.Comparator;
public class Demo1_Comparator {
public static void main(String[] agrs) {
Student arr[] = {new Student("张三",19,90.1f),
new Student("李四",18,90.1f),
new Student("赵六",20,60.1f),
new Student("李超武",20,70.1f)};
java.util.Arrays.sort(arr);
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
class Student implements Comparable<Student> {
private String name;
private int age;
private float score;
public Student(String name,int age,float score) {
this.name = name;
this.age = age;
this.score = score;
}
public String toString() {
return "姓名:" + name + " 年龄:" + age + " 分数:" + score;
}
public int compareTo(Student s1) {
if(this.score > s1.score ) {
return 1;
}else if(this.score < s1.score) {
return -1;
} else {
if(this.age > s1.age) {
return 1;
}else if(this.age < s1.age) {
return -1;
}else {
return 0;
}
}
}
}
- 分析比较器的原理
1、比较器的底层实际上是用二叉树的排弃算法;
2、排弃原理:使用第一个元素做为根节点;之后元素如果内容比根节点小,就放左子树,大就放右子树;之后使用中弃遍历读取出来; - 实现一个二叉树的比较算法
package com.lichaowu.comparator;
class BinaryTree2 {
class Node {
private Comparable data;
private Node left;
private Node rigth;
public Node(Comparable data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.data.compareTo(newNode.data) < 0) {
if(this.left == null) {
this.left = newNode;
}else {
this.left.addNode(newNode);
}
}
if(this.data.compareTo(newNode.data) >= 0) {
if(this.rigth == null) {
this.rigth = newNode;
}else {
this.rigth.addNode(newNode);
}
}
}
public void printNode() {
if(this.left != null) {
this.left.printNode();
}
System.out.println(this.data);
if(this.rigth != null) {
this.rigth.printNode();
}
}
};
private Node root;
public void add(Comparable data) {
Node newNode = new Node(data);
if(root == null) {
root = newNode;
}else {
root.addNode(newNode);
}
}
public void print() {
this.root.printNode();
}
};
public class Demo4_Test {
public static void main(String[] agrs) {
BinaryTree2 bt2 = new BinaryTree2();
bt2.add(new StudentDemo("李超武",19,100.0));
bt2.add(new StudentDemo("陈清香",20,90.2));
bt2.add(new StudentDemo("吴非凡",21,50.2));
bt2.add(new StudentDemo("阳文杰",18,11.2));
bt2.add(new StudentDemo("谢仔晟",19,101.0));
bt2.print();
}
}
class StudentDemo implements Comparable<StudentDemo>{
private String name;
private int age;
private double score;
public StudentDemo(String name,int age,double score) {
this.name = name;
this.age = age;
this.score = score;
}
public String toString() {
return "我的姓名: " + name + " 我的年龄是: " + age
+ " 我的分数是: " + score;
}
public int compareTo(StudentDemo stu) {
if(this.score > stu.score) {
return 1;
}else if(this.score < stu.score){
return -1;
}else {
if(this.age > stu.age) {
return 1;
}else if(this.age < stu.age){
return -1;
}else {
return 0;
}
}
}
}
//超级有意思............
//没有写注释
- java.util.Comparator(第三方比较器)
1、如果一个类已经开发完成,但没有实现Comparable接口,就不能实现对对象进行排序;所以为了解决这种问题,java又定义了另一种比较器Comparator;需重写compare()方法;实现如下
package com.lichaowu.comparator;
import java.util.Comparator;
class StudentDemo1 {
private String name;
private int age;
public StudentDemo1(String name,int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof StudentDemo1)) {
return false;
}
StudentDemo1 stu = (StudentDemo1)obj;
if(stu.name.equals(this.name) && stu.age == this.age) {
return true;
} else {
return false;
}
}
public String toString() {
return "姓名: " + name + "年龄: " + age;
}
}
class StudentComparator implements Comparator<StudentDemo1> {
public int compare(StudentDemo1 s1,StudentDemo1 s2) {
if(s1.equals(s2)) {
return 0;
}else if(s1.getAge() < s2.getAge()) {
return 1;
}else {
return -1;
}
}
}
public class Demo5_Comparator {
public static void main(String[] agrs) {
StudentDemo1[] arr = {
new StudentDemo1("李超武",19),
new StudentDemo1("张三",20),
new StudentDemo1("李四",30),
new StudentDemo1("吴非凡",9),
};
java.util.Arrays.sort(arr, new StudentComparator());
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
- 注意:在使用中最好还是使用Comparable在需要排序的类上实现好此接口,而Comprator需要单独建立一个排序的类,则排弃的规则类也就非常多,操作麻烦,只要是对象排序,则在Java中都是以Comparable接口为准的
观察者设计模式
- 什么是观察者设计模式
“现在很多的购房者(Observer)都在关注房子(Observable)的价格变化,每当房子价格变化时,所有购房者都属于观察者都观察得到”,实际上以上的购房者都是观察者,他们都关注房子价格;
- 如果要实现观察者设计模式,则依靠java.util.Observer接口&&java.util.Observable类
- 如下
package com.lichaowu.observer;
import java.util.Observable;
import java.util.Observer;
//表示房子可以被观察
class House extends Observable { //继承Observable
private double price; //价钱
public House(double price) {
this.price = price;
}
public void setPrice(double price) {
//每一次修改都引起观察者的注意
super.setChanged(); //设置变化点
super.notifyObservers(price); //告诉所有观察者价格被修改
this.price = price;
}
public double getPrice() {
return this.price;
}
public String toString() {
return "房子价格为: " + this.price;
}
};
class HousePriceObserver implements Observer {
private String name;
public HousePriceObserver(String name) { //设置观察者名字
this.name = name;
}
public void update(Observable o,Object arg) {
if(arg instanceof Double) {
System.out.print(this.name + "观察到价格更改为:");
System.out.println(((Double)arg).floatValue());
}
}
};
public class Demo1_Observer {
public static void main(String[] agrs) {
House h = new House(1000000);
HousePriceObserver hpo1 = new HousePriceObserver("张三");
HousePriceObserver hpo2 = new HousePriceObserver("李四");
HousePriceObserver hpo3 = new HousePriceObserver("王五");
h.addObserver(hpo1);
h.addObserver(hpo2);
h.addObserver(hpo3);
System.out.println(h);
h.setPrice(6666666);
System.out.println(h);
}
}
定时调用(Timer&&TimerTask)
- 定时调度:每当一段时间,程序就会自动执行,称为定时调度;
- 如果要使用定时调度,则必须保证程序始终运行,也就是说相当于定时调度是在程序之外又启动了一个新的线程;
- 使用Timer&&TimerTask实现定时调度
- Timer类:是一种线程设施,可以用来实现在某一个时间或某一段时间后,安排某一个任务执行一次,或定期重复执行多次,该功能要与TimerTask配合使用。
- TimerTask类:用来实现Timer安排的一次或重复执行的某个任务。
- 第一个Timer对象对应一个线程,因此计时器所执行的任务应该迅速完成,否则可能会延迟后继的任务的执行,而这些后继的任务就有可能堆在一起。等到该任务完成后才能快速连续的执行
- Timer类中schedule()方法与scheduleAtFixedRate的区别
两者的区别在与重复执行任务时,对于时间间隔出现延迟的情况处理
schedule()方法执行的时间都是固定的,如果之前出现了延迟的情况,之后也会继续按照设定好的间隔时间来执行
scheduleAtFixedRate()方法可以根据出现的延迟时间自动调整下一次间隔的执行时间 - TimerTask类要想执行具体的任务,则必须使用TimerTask(抽象类)的子类,实现其中的抽象方法;其实就一个run()抽象方法,和线程一样;
package com.lichaowu.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Demo_Timer {
public static void main(String[] args) {
Timer t = new Timer(); //建立Timer对象
MyTimer mt = new MyTimer(); //定义任务
t.schedule(mt, 1000,2000); //设置mt这个任务1秒后开始执行每隔2秒执行一次
}
}
/**
* 如果现在一个Timer类想要调度程序的话,则需使用TimerTask的子类,并重写run()
* 依照此概念,完成一个定时调度,每隔2 秒打印一次系统时间
* @author fhvk.game
* */
class MyTimer extends TimerTask {
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss.SSS");
System.out.println("当前系统时间: " + sdf.format(new Date()));
}
}
- 总结:一般在web的开发中此内容比较有用,因为要维护一个容器不关闭才可以一直定时下去;
一些面试题
- 使用已知的变量,在控制台输出30,20,10;代码如下:
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public viod show() {
int num = 30;
System.out.println(?); //同名量就近原则直接写num;
System.out.println(??); //num = 20属于成员变量直接this.num 调用;
System.out.println(???); //Outer.this.num 意思是限定了范围Outer.
}
}
}
- 按照要求补齐代码,要求在控制台输出"Hello World!";
class Test {
public static void main(String[] agrs) {
Outer.method().show();
}
}
interface Inter {
public abstract void show();
}
class Outer() {
//补齐代码
public static Inter method() {
return new Inter() {
public show() {
System.out.println("Hello World!");
}
};
}
}
- String比较
1.判断定义为String类型的s1和s2是否相等?
String s1 = "abc"; //在常量池创建一个"abc";
String s2 = "abc"; //常量池特点:有一模一样就不再创建
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
2,下面这句话在内存中创建了几个对象?
String s1 = new String("abc"); /*两个;先在常量池中创建一个"abc",再在堆内在new一个String();*/
3.判断定义为String类型的s1和s2是否相等?
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); /* false 比较地址,一个在堆,一个常量池,地址肯定不一样*/
System.out.println(s1.equals(s2)); //true比较的是字符序列,肯定相等
4.判断定义为String类型的s1和s2是否相等?
String s1 = "a" + "b" + "c"; //在编译时就变成了"abc"
String s2 = "abc"; //所以这里不用再创建
System.out.println(s1 == s2); //true. java中有常量优化机制
System.out.println(s1.equals(s2)); //true. 比较字符序列
5,判断定义为String类型的s1和s2是否相等?
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c"; //java常量优化机制,但s1是变量对象;
System.out.println(s2 == s3); //false
System.out.println(s2.equals(s3)); //true;
java中"+"连接其它数据类型时,底层都会在堆内存创建一个StringBuffer缓冲区通过append方法添加进来,然后通过toString方法返回回去;
- StringBuffer和StringBuilder的a别&&String和StringBuffer、StrringBuilder的区别?
StringBuffer和StringBuilder的区别:StringBuffer是线程安全的,效率底,StringBuilder是线程不安全的,效率高;
String 与 StringBuffer和StringBuilder的区别:
String:不可变字符序列
StringBuffer、StringBuilder:可变字符序列;
- 看程序写结果
Integer i1 = new Integer(97);
Integer i2 = new Integer(97);
System.out.println(i1 == i2); //false 比较的是地址
System.out.println(i1.equals(i2)); //true. 比较的是基本数据类型值,Integer包装类重写了equals();
Integer i3 = 127;
Integer i4 = 127;
System.out.println(t3 == t4); //true
System.out.println(t3.equals(t4)); //true;
Integer i5 = 128;
Integer i6 = 128;
System.out.println(t5 == t6); //false
System.out.println(t5.equals(t6)); // true
-注意:自动装箱在byte的取值范围就不会创建对象,直接在常量池拿; -128~127;
- Math.round(11.5)等于多少?Math.round(-11.5)又等于多少?
答:round()方法有四舍五入的效果;分别是12和-11;返回的是long
扩展:
1、Math.ceil()向上取整;返回一个double
2、Math.floor()向下取整;返回一个double
- switch是否能作用在byte上?是否能作用在long上?是否能作用在String上?
答:按jdk1.7后;不支持long,其它都支持;
jdk1.7:shrot,int,byte,String,char,enum;
- 数组有没有length()方法?String有没有length()方法?
答:数组中的length是属性不是方法,所以没有length()方法,String有length()方法!
- String、StringBuffer、StringBuilder的区别?
答:String是不可变字符序列;
StringBuffer、StringBuilder是可变;
StringBuffer是线程安全,效率没StringBuilder高;方法全被synchronized修饰;
StringBuilder是线程不安全的,效率高;
- 什么情况下用"+"运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append()方法字符串连接性能更好?
答:在相+次数较少的情况下使用+影响应该不大
看了很多觉得很全面:https://blog.csdn.net/yyqhwr/article/details/79715614
- 用最有效的方法计算2*8?
答:2<<3(左移相当于*2的3次方,右移相当于/2的3次方)
- 使用递归实现字符串反转?
public class Test17 {
public static void main(String[] agrs) {
String str = "12345678";
String str1 = reverse(str);
System.out.println(str1);
}
public static String reverse(String str) {
if(str == null || str.length() <= 1) {
return str;
}
return new StringBuilder(reverse(str.substring(1))).append(str.charAt(0)).toString();
}
}
- 日期和时间
2. 打印昨天的当前时间
improt java.util.Calendar;
class Test18 {
public static void main(String[] agrs) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH,-1);
}
}