一、接口interface关键字
1.1概述
Java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。
Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为java结构层次上的顶层。
interface 接口名{ 代码… }
1.2特点
1、 通过interface关键字创建接口
2、 通过implements让子类来实现
3、 接口是一个特殊的抽象类,接口里的方法都是抽象方法。
4、 接口突破了java单继承的局限性,可以多继承,多实现。
5、 接口和类之间可以多实现,接口和接口之间可以多继承
6、 接口是对外暴露的规则,是一套开发规范
7、 接口提高了程序的功能扩展,降低了耦合性
8、接口和抽象类都不能new,接口里面是没有构造方法的,接口里面没有成员变量,都是常量。
接口里面可以有抽象方法,普通方法,仅支持default和static(jdk1.8提供的新语法)。
package cn.tedu.oop;
//测试 接口
public class Test1 {
public static void main(String[] args) {
// new fu();//接口不能new 抽象类也不行
fu f = new zi();
f.eat();
f.show();
}
}
interface fu{
public abstract void eat();
public abstract void show();
public static final int AGE = 10;
}
class zi implements fu{
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void show() {
System.out.println("做节目");
}
}
package cn.tedu.oop;
//测试 接口的使用,成员变量,构造方法,普通方法,静态
public class Test2 {
public static void main(String[] args) {
A a = new B();
a.show();
System.out.println(A.NAME);
}
}
interface A{
// public A() {
// //接口中不能有构造方法
// }
// int age ;//接口中不能有成员变量
public static final String NAME = "王林";//接口中可以有静态不可改的常量
void show();//抽象方法
// abstract public void show();//抽象方法的全写和简写
static void demo() {
System.out.println("普通方法");//仅支持default和static
}
}
class B implements A{
@Override
public void show() {
System.out.println("重写父类show");
}
}
package cn.tedu.oop;
//接口的复杂用法
public class Test3 {
public static void main(String[] args) {
}
}
interface C{
public abstract void save();//抽象方法
}
interface C1{
void get(int id);
}
//接口突破java单继承的局限性,接口间发生
interface C2 extends C,C1{
void del();
}
//实现类可以在继承的同时多实现,实现类必须重写所有的抽象方法,否则是一个抽象类
class C4 extends Object implements C,C1{
@Override
public void get(int id) {
}
@Override
public void save() {
}
}
//实现类和接口是 实现关系, 可以多实现
//必须重写 所有抽象方法 否则就是一个抽象类
class C3 implements C,C1,C2{
@Override
public void save() {
System.out.println("保存");
}
@Override
public void get(int id) {
System.out.println("获取");
}
@Override
public void del() {
System.out.println("删除");
}
}
1.3总结
1、 类与类的关系:
-- 是继承关系,java只支持单继承 class A extends B
2、 类和接口的关系:
-- 实现关系 class x implements A
-- 类需要把A接口里的所有抽象方法重写
-- 多实现 class x implements A,B
-- 类需要把A,B接口里的所有抽象方法重写
-- 可以在继承的同时多实现,注意要先继承后实现
//A是类,B也是类,C和D是接口
class A extends B implements C,D{
3、 接口和接口的关系:
-- 继承关系 interface c extends A
-- 多继承 interface c extends A,B
二、API
2.1Object
2.1.1常用方法
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。
使用==进行比较
==比基本类型,直接比较值本身
==比引用类型,直接比较地址值,如果new过,则地址值不同。
int hashCode() 返回该对象的哈希码值。
String toString() 返回该对象的字符串表示。
package cn.tedu.api;
//测试 Object工具类
public class Test1 {
public static void main(String[] args) {
Object o = new Object();//触发无参构造
//返回该对象的字符串表示
System.out.println(o.toString());//展示地址值java.lang.Object@60f82f98
//指示其他某个对象是否与此对象“相等”
System.out.println(o.equals("jack"));
//返回该对象的哈希码值
System.out.println(o.hashCode());//1626877848
}
}
创建Student类
package cn.tedu.api;
public class Student {
private int age;
private String name;
public Student() {
System.out.println("无参构造");
}
public Student(String name,int age) {
//给成员变量赋值
this.age = age;
this.name = name;
System.out.println("含参构造");
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
// public void setAge(int age) {
// this.age = age;
// }
public String getName() {
return name;
}
// public void setName(String name) {
// this.name = name;
// }
}
2.1.2Object的复杂用法
package cn.tedu.api;
//测试 api中 Object工具类的复杂用法
public class Test2 {
public static void main(String[] args) {
Student s = new Student("王林",24);
System.out.println(s);
Student s1 = new Student("王林",24);
System.out.println(s.equals(s1));
}
}
2.2String
2.2.1常用方法
length()返回此字符串的长度。
charAt()根据下标获取对应的字符。
lastIndexOf()返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
substring()返回一个新的字符串,它是此字符串的一个子字符串。
equals()将此字符串与指定的对象比较。
startsWith()测试此字符串是否以指定的前缀开始。
endsWith()测试此字符串是否以指定的后缀结束。
split()根据给定正则表达式的匹配拆分此字符串。
trim() 去除字符串两端的空格。
package cn.tedu.api;
import java.util.Arrays;
//测试 String 工具类
public class Test3 {
public static void main(String[] args) {
String s = new String();//触发无参构造
System.out.println(s);
char [] value = {'h','E','l','L','o'};
String s2 = new String(value);//触发含参构造
System.out.println(s2);
//char cahrAt(int index)//根据下标获取对应的字符O
System.out.println(s2.charAt(4));
//String concat(String str)//拼接字符串
System.out.println(s2.concat("123"));
//boolean endsWith(String suffix)//判断s2是否以”lo“结尾
System.out.println(s2.endsWith("lo"));
//boolean contains(CharSequence s)此字符串包含指定的 char 值序列时,返回 true
System.out.println(s2.contains("he"));
// boolean equals(Object anObject)//将此字符串与指定的对象比较
System.out.println(s2.equals("hElLo"));
// int hashCode() //返回此字符串的哈希码
System.out.println(s2.hashCode());
// int indexOf(String str)子字符串在此字符串中第一次出现处的索引。
System.out.println(s2.indexOf("l"));
// int lastIndexOf(String str) 子字符串在此字符串中最右边出现处的索引。
System.out.println(s2.lastIndexOf("o"));
// boolean isEmpty() //当且仅当 length() 为 0 时返回 true。
System.out.println(s2.isEmpty());
// int length()//返回此字符串的长度。
System.out.println(s2.length());
// boolean matches(String regex) 此字符串是否匹配
System.out.println(s2.matches("he"));
// String replace(char oldChar, char newChar)
//它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
System.out.println(s2.replace("h", "demo"));
// boolean startsWith(String prefix) 此字符串是否以指定的前缀开始。
System.out.println(s2.startsWith("h"));
//String substring(int beginIndex) 从4索引开始截取子串
System.out.println(s2.substring(4));
//String substring(int beginIndex, int endIndex)
//从索引1开始,到4结束截取子串[0,4)-含头不含尾
System.out.println(s2.substring(0, 4));
// String toLowerCase() 将此 String 中的所有字符都转换为小写。
System.out.println(s2.toLowerCase());
// String toUpperCase() 将此 String 中的所有字符都转换为大写。
System.out.println(s2.toUpperCase());
// String trim() 去掉多余空格
System.out.println(s2.trim());
// static String valueOf(double d) 把其他类型转成String类型
System.out.println(s2.valueOf(1.2));
// byte[] getBytes() 把每个字符对应的数字存入btye[]
byte[] bs = s2.getBytes();
System.out.println(Arrays.toString(bs));
// String[] split(String regex) 按照规则切割字符串
String [] ss = s2.split(" ");
System.out.println(Arrays.toString(ss));
// char[] toCharArray() 把字符串里的字符,存入char[]
System.out.println(Arrays.toString(s2.toCharArray()));
String m = "abcdefghjklmn";
//变成char[],再遍历char[]
char [] n = m.toCharArray();
for(int i=0;i<n.length;i++) {
System.out.print(n[i]+" ");
}
System.out.println();
//变成byte[] ,再遍历byte[]
byte [] m1 = m.getBytes();
for(int i=0;i<m1.length;i++) {
byte da =m1[i];
char n1 = (char)da;
System.out.print(n1+" ");
}
System.out.println();
//直接遍历字符串,获取里面的字符
for(int i=0;i<m.length();i++) {
char da = m.charAt(i);
System.out.print(da+" ");
}
}
}
2.3StringBuilder/StringBuffer用来解决字符串拼接的
2.3.1特点
1、 封装了char[]数组
2、 是可变的字符序列
3、 提供了一组可以对字符内容修改的方法
4、 常用append()来代替字符串做字符串连接
5、 内部字符数组默认初始容量是16:initial capacity of 16 characters
6、 如果大于16会尝试将扩容,新数组大小原来的变成2倍+2,容量如果还不够,直接扩充到需要的容量大小。int newCapacity = value.length * 2 + 2;
7、 StringBuffer 1.0出道线程安全,StringBuilder1.5出道线程不安全
package cn.tedu.api;
//测试 StringBuilder/StringBuffer
public class Test1 {
public static void main(String[] args) {
// method();//用+拼接
method1();//
}
private static void method1() {
StringBuilder sb = new StringBuilder();
String a = "abcd123";
long start = System.currentTimeMillis();
for(int i=0;i<100000;i++) {
sb.append(a);
}
long end = System.currentTimeMillis();
System.out.println(end-start+"毫秒");
}
private static void method() {
String a = "abcd123";
String res = "";
long start = System.currentTimeMillis();
for(int i=0;i<1000;i++) {
res = res+a;
}
long end = System.currentTimeMillis();
System.out.println(end-start+"毫秒");
}
}
2.4日期类Date
2.4.1概述
存在于java.util.Date包。
用来封装一个毫秒值表示一个精确的时间点。
从1970-1-1 0点开始的毫秒值。
2.4.2常用方法
package cn.tedu.api;
//测试 date工具类
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
//date用来获取时间的年月日时分秒毫秒
//SimpleDateFormat--用来把String 类型的日期和date类型的日期互转
public class Test2 {
public static void main(String[] args) throws Exception {
// method();//date
method1();//string->date
}
private static void method1() throws Exception {
System.out.println("请输入用户出生日期");
String b = new Scanner(System.in).nextLine();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sf.parse(b);
long start = d.getTime();//获取出生时间
long end = System.currentTimeMillis();//获取当前时间
System.out.println((end-start)/1000/60/60/24/365);
}
private static void method() {
Date d = new Date();//使用当前时间
System.out.println(d.getTime());//返回1970.1.1零点的毫秒值
System.out.println(d.getYear());//从1900年开始算
System.out.println(d.getDate());//今天是几号
System.out.println(d.getDay());//今天礼拜几
System.out.println(d.getMinutes());//获取分钟
System.out.println(d.getMonth());//获取月份
System.out.println(d.toLocaleString()); //变成当前时间
}
}
2.5日期工具SimpleDateFormat
2.5.1概述
日期格式化工具,可以把Date对象格式化成字符串,也可以日期字符串解析成Date对象。
2.5.2常用方法(代码在上面2.4里面)
format(Date):把Date格式化成字符串
parse(String):把String解析成Date
2.6BigDecimal/BigInteger
2.6.1概述
BigDecimal:专门解决小数运算不精确的问题。
BigInteger:常用来解决超大的整数运算。
2.6.2常用方法
add(BigDecimal bd): 做加法运算
substract(BigDecimal bd) : 做减法运算
multiply(BigDecimal bd) : 做乘法运算
divide(BigDecimal bd) : 做除法运算
divide(BigDecimal bd,保留位数,舍入方式):除不尽时使用
setScale(保留位数,舍入方式):同上
pow(int n):求数据的几次幂
package cn.tedu.api;
import java.math.BigDecimal;
import java.util.Scanner;
//测试 bigdecimal工具类
public class Test3 {
public static void main(String[] args) {
// method();
method1();
}
private static void method1() {
System.out.println("请输入第一个小数");
double a = new Scanner(System.in).nextDouble();
System.out.println("请输入第二个小数");
double b = new Scanner(System.in).nextDouble();
//方式1:BigDecimal(double val),有坑不能用
//解决运算不精确
// BigDecimal bd = new BigDecimal(a);
// BigDecimal bd1 = new BigDecimal(b);
//方式2:推荐使用BigDecimal(String val)
//把参数,从double-->String----1.String.valueOf()----2.+""
BigDecimal bd = new BigDecimal(String.valueOf(a));
BigDecimal bd1 = new BigDecimal(b+"");
//调用方法
//加法
System.out.println(bd.add(bd1));
//减法
System.out.println(bd.subtract(bd1));
//乘法
System.out.println(bd.multiply(bd1));
//除法 java.lang.ArithmeticException除不尽bug
System.out.println(bd.divide(bd1,2,BigDecimal.ROUND_HALF_UP));
}
private static void method() {
System.out.println("请输入第一个小数");
double a = new Scanner(System.in).nextDouble();
System.out.println("请输入第二个小数");
double b = new Scanner(System.in).nextDouble();
System.out.println(a+b);//不精确
System.out.println(a-b);//不精确
System.out.println(a*b);//不精确
System.out.println(a/b);//不精确
}
}
2.7包装类
父类:Number数字包装类的抽象父类(前6个)。
package cn.tedu.api;
//测试 Integer 包装类
public class Test4 {
public static void main(String[] args) {
//创建对象---把基本类型 变成 包装类型
Integer i = new Integer(5);
//调用intvalue方法
System.out.println(i.intValue());//把包装类型 变成 基本类型
//调用parseInt方法静态的
System.out.println(Integer.parseInt("5"));//把字符串转成基本类型
//调用valueOf方法静态的
System.out.println(Integer.valueOf(5));//把基本类型转成包装类型
Double d = new Double(2.3);//把double基本类型 变成 包装类型
Double d1 =Double.valueOf(d);
System.out.println(d.doubleValue());//包装类型变成基本类型
}
}
三、拓展
3.1抽象类abstract的注意事项
抽象方法要求子类继承后必须重写。那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。
1、 private:被私有化后,子类无法重写,与abstract相违背。
2、 static:静态的,优先于对象存在。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。
3、 final:被final修饰后,无法重写,与abstract相违背。
3.2接口和抽象类的区别
1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
7、抽象类里可以没有抽象方法,如果要扩展抽象类的新方法,子类将很容易的就能得到这些新方法。
8、如果一个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可继承接口,并可多继承接口,但类只能单根继承。
3.3了解软件设计的开闭原则OCP
开放功能扩展,关闭源码修改。等
开闭原则的英文全称是Open Close Principle,缩写是OCP,它是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。
开闭原则的定义是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。
开闭原则,是一种设计模式,随着面向对象程序设计的思想,应运而生。
开,指的是可以在源代码的基础上进行扩展,比如继承,接口,抽象类等。在JAVA中,之所以用继承,是在可以直接调用类库的前提下,对其功能进行扩展。不需要应用者去了解封装类的内部逻辑就可以做开发。
闭:指不允许对原有的代码进行修改。以免影响其他现有功能,造成功能瘫痪。
3.4StringBuilder和StringBuffer的区别
1、 在线程安全上,
--StringBuffer是旧版本就提供的,线程安全的。@since JDK1.0
--StringBuilder是jdk1.5后产生,线程不安全的。@since 1.5
2、 在执行效率上,StringBuilder > StringBuffer > String
3、 源码体现:本质上都是在调用父类抽象类AbstractStringBuilder来干活,只不过Buffer把代码加了同步关键字,使得程序可以保证线程安全问题。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
3.5自动装箱和自动拆箱
自动装箱:把基本类型包装成一包装类的对象
Integer a = 5;//a是引用类型,引用了包装对象的地址。
编译器会完成对象的自动装箱:Integer a = Integer.valueOf(5);
自动拆箱:从包装对象中,自动取出基本类型值
int i = a;//a现在是包装类型,没法给变量赋值,需要把5取出来。
编译器会完成自动拆箱:int i = a.intValue();