day06-03 接口
当一个类中的所有方法都是抽象方法的时候,我们就可以将其定义为接口。接口也是一种引用数据类型,它比抽象类还要抽象
接口存在的两个重要意义:
1.规则的定义
2.程序的扩展性
接口用关键字interface来定义
public interface 接口名{}
接口不能实例化
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}
接口的子类(实现类):
要么重写接口中的所有抽象方法,要么是抽象类
接口中成员的特点:
成员变量:接口中的变量默认被public final static修饰
构造方法:没有
成员方法:只能是抽象方法,系统会默认加上public abstract
jdk8后
允许在接口中定义非抽象方法,但是需要使用关键字default修饰,这些方法就是默认方法
接口中允许定义static静态方法
接口中默认方法的定义格式:
格式:public default 返回值类型方法名(参数列表){}
public default void show(){}
接口中默认方法的注意事项:
默认方法不是抽象方法,所以不强制被重写,但是可以被重写,重写的时候去掉default关键字
public可以省略,default不能省略
如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
public interface InterA {
public default void show(){//不加default会报错
System.out.println("A接口中的默认方法");
}
}
public class TestInterface {
public static void main(String[] args) {
InterAImpl ia=new InterAImpl();
ia.show();//实现类可以直接使用接口中的默认方法,重写后执行重写后的方法
}
}
class InterAImpl implements InterA{
@Override
public void show() {//重写接口中的默认方法不要加default
System.out.println("重写后的接口A的默认方法");
}
}
JKD9版本中接口成员的特点
接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表){}
范例1:private void show()
格式2:private static 返回值类型 方法名(参数列表){}
范例2:private static void method(){}
接口的使用思路:
如果发现一个类中所有的方法都是抽象方法,那么就可以将该类改进为一个接口
涉及到了接口大面积更新方法,而不想去修改每一个实现类,就可以将更新的方法定义为带有方法体的默认方法
希望默认方法调用的更加简洁,可以考虑设计为static静态方法(需要去掉default关键字)
默认方法中出现了重复的代码,可以考虑抽取出一个私有方法(需要去掉default关键字)
类和接口的关系
类和类:继承关系,只能单继承,但是可以多层继承
类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口和接口的关系:继承关系,可以单继承,也可以多继承
InterImpl extends Fu implements Inter,且Fu和Inter中都有同名show方法,调用时调的是Fu中的show方法
day06-12 多态
同一个对象在不同时刻表现出来的不同形态
多态的前提和体现:有继承/实现关系,有方法重写,有父类引用指向子类对象
多态中成员访问特点
构造方法:同继承一样,子类会通过super访问父类构造方法
成员变量:编译看左边(父类),执行看左边(父类)
成员方法:编译看左边(父类),执行看右边(子类)
不一样是因为成员方法有重写而成员变量没有
public class Test1Polymorpic {
public static void main(String[] args) {
Fu fu=new Zi();
System.out.println(fu.num);//父类里没有会报错,拿的也是父类的值
fu.method();//父类里没有会报错,但实际执行的是子类的方法
}
}
class Fu {
int num=10;
public void method(){
System.out.println("Fu method");
}
}
class Zi extends Fu{
int num=20;
public void method(){
System.out.println("Zi method");
}
}
多态的优点:提高了程序的扩展性
具体体现:定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的任意子类对象
多态的弊端:不能使用子类的特有功能
public class Test2Polymorpic {
public static void main(String[] args) {
//1.向上转型:父类引用指向子类对象
Fu f=new Zi();
f.show();
//f.method()//多态的弊端:不能调用子类特有的方法
//想调用子类方法:1.直接创建子类对象 2.向下转型
//2.向下转型:从父类转换回子类
Zi z=(Zi) f;
z.method();
}
}
class Fu {
public void show(){
System.out.println("Fu...show");
}
}
class Zi extends Fu{
@Override
public void show(){
System.out.println("Zi...show");
}
public void method(){
System.out.println("子类特有方法method");
}
}
如果被转的引用类型变量对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
用instanceof判断一下是不是那个类型再转
day07-01 内部类
内部类就是在一个类中定义一个类
public class Outer{
public class Inner{
}
}
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建
内部类的形式:
在类的成员位置:成员内部类
在类的局部位置:局部内部类
外界创建对象使用:
外部类名.内部类名 对象名=new 外部类对象().new 内部类对象();
私有成员(private)内部类访问:在自己所在的外部类中创建对象访问
static(静态)内部类访问:外部类名.内部类名 对象名=new 外部类名.内部类名();
static(静态)内部类中的静态方法:外部类名.内部类名.方法名();
public class Test1Inner {
public static void main(String[] args) {
// Inner inner=new Inner();//报错,编译器不知道这个Inner归属于哪个外部类
/*
创建内部类对象的格式:
外部类名.内部类名 对象名=new 外部类对象().new 内部类对象();
*/
Outer.Inner i=new Outer().new Inner();
System.out.println(i.num);
i.show();
}
}
class Outer{
int numOuter=10;
private int numPrivate=20;
class Inner{
int num=10;
public void show(){
System.out.println("Inner..show");
//内部类可以直接放完外部类的私有和成员变量
System.out.println(numOuter);
System.out.println(numPrivate);
}
}
}
class Outer2{
class Inner{
int num=10;
public void show(){
System.out.println("Inner..show");
}
}
}
私有成员内部类
public class Test3Innerclass {
/*私有成员内部类*/
public static void main(String[] args) {
//Outer.Inner oi=new new Outer().new Inner();
//报错,被private修饰的类只能在本类内进行访问
//解决方法:去外部类里访问
Outer o=new Outer();
o.method();
}
}
class Outer{
private class Inner{//成员内部类可以使用private
public void show(){
System.out.println("Inner..show");
}
}
public void method(){
Inner i=new Inner();
i.show();
}
}
静态成员内部类
public class Test2Innerclass {
/*
静态成员内部类
*/
public static void main(String[] args) {
//Outer.Inner oi=new Outer().new Inner();
//报错
Outer.Inner oi=new Outer.Inner();
//访问静态方法
Outer.Inner.method();
}
}
class Outer{
static class Inner{
public void show(){
System.out.println("Inner..show");
}
public static void method(){
System.out.println("Inner..method");
}
}
}
局部内部类
局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
public class Test4Innerclass {
/*
局部内部类:
编写位置:方法中
访问方式:只能在方法中创建对象并访问
*/
public static void main(String[] args) {
}
}
class Outer{
int a=10;
public void method(){
int b=20;
class Inner {
public void show(){
System.out.println("show...");
System.out.println(a);
System.out.println(b);
}
}
Inner i=new Inner();
i.show();
}
}
匿名内部类
本质上是一个特殊的局部内部类
前提:需要存在一个接口或类
本质:将继承\实现,方法重写,创建对象,放在了一步执行
格式:
new 类名或接口名(){
重写方法;
}
new Inter(){
public void show(){
}
}
public class Test5Innerclass {
/*
实现接口:
1.创建实现类,通过implements关键字去实现接口
2.重写方法
3.创建实现类对象
4.调用重写后的方法
匿名内部类实现接口:
前提:需要存在类\接口
格式:new 类名\接口名(){
重写方法
}
*/
public static void main(String[] args) {
InterImpl ii=new InterImpl();
ii.show();
//匿名内部类:将继承\实现,方法重写,创建对象,放在了一步执行
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类中的show方法");
}
}.show();
//接口中存在多个方法,就用父类接口接一下(多态)
Inter2 inter2 = new Inter2() {
@Override
public void show1() {
System.out.println("show1");
}
@Override
public void show2() {
System.out.println("show2");
}
};
inter2.show1();
inter2.show2();
}
}
interface Inter {
void show();
}
interface Inter2 {
void show1();
void show2();
}
class InterImpl implements Inter{
@Override
public void show() {
System.out.println("InterImpl重写的show方法");
}
}
day07-06 lambda
public class TestSwimming {
public static void main(String[] args) {
/*匿名内部类方式*/
goSwimming(new Swimming(){
@Override
public void swim(){
System.out.println("游泳重写");
}
});
/*lambda是对匿名内部类进行优化,但本质上有区别*/
goSwimming(()->{
System.out.println("lambda重写");
});
}
/*使用接口的方法*/
public static void goSwimming(Swimming swimming){
swimming.swim();
}
}
/* 游泳接口*/
interface Swimming{
void swim();
}
lambda表达式的代码分析
() :里面没有内容,可以看成是方法形式参数为空,如果有多个参数,参数之间用逗号隔开
->:用箭头指向后面要做的事情
{} :包含一段代码,我们称之为代码块,可以看成是方法体中的内容
lambda表达式的使用前提:
1.有一个接口
2.接口中有且仅有一个抽象方法
//无参无返回值
goSwimming(()->{
System.out.println("lambda重写");
});
//有参无返回值
goSwimming((String msg)->{
System.out.println("lambda重写"+msg);
});
//无参有返回值
goSwimming(()->{
System.out.println("lambda重写"+msg);
return "123";
});
//有参有返回值
goSwimming((a,b)->{
System.out.println("lambda重写"+msg);
return a+b;
});
Lambda表达式的省略模式
1.参数类型可以省略,但是有多个参数的情况下,不能只省略一个
2.如果参数有且仅有一个,那么小括号可以省略
3.如果代码块的语句只有一条,可以省略大括号和分号,甚至是return
Lambda表达式和匿名内部类的区别
1.所需类型不同
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
Lambda表达式:只能是接口
2.使用限制不同
如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
3.实现原理不同
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:编译之后,没有一个单独的.class字节码文件,对应的字节码会在运行的时候动态生成
day07-13 API
Math类里的方法全是static方法所以可以用Math.方法名调用
abs:绝对值
ceil:向上取整
floor:向下取整
round:四舍五入
max:俩值里大的
min:俩值里小的
pow:幂
System也全是static方法
public static void exit(int status):终止当前运行的java虚拟机,非0表示异常终止
public static long currentTimeMillis():返回当前时间(以毫秒为单位)
arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数)
Object:
Object类是所有类的直接或者间接父类,直接打印一个对象就是打印这个对象的toString方法的返回值,而Object类的toString方法得到的是对象的地址值,所以一般会重写toString方法
常用方法:
public String toString()
public boolean equals()
== 比较引用类型比的是地址,Object类底层equals也是==判断的
Objects类的常用方法:
public static String toString(对象):返回参数中对象的字符串表现形式
public static String toString(对象,默认字符串):返回对象的字符串表示形式(是空返回默认字符串,不是空返回对象)
public static Boolean isNull(对象):判断对象是否为空
public static Boolean nonNull :判断对象是否不为空
BigDecimal
构造方法可以把字符串和整数转成BigDecimal类型,如果要精确计算,需要使用字符串的构造
方法:
public BigDecimal add(另一个BigDecimal对象) :加法
public BigDecimal substract(另一个BigDecimal对象) :减法
public BigDecimal multiply(另一个BigDecimal对象) :乘法
public BigDecimal divide(另一个BigDecimal对象) :除法
public BigDecimal divide(另一个BigDecimal对象,精确几位,舍入模式) :除法