面向对象补充

一、JDK8和JDK9接口的新特性

(一)接口新特性

1.JDK8接口特性

(1)允许在接口中定义非抽象f方法,但是需要使用关键字default修饰,这些方法就是默认方法。

▶ 作用:解决接口升级的问题

▶ 接口中默认方法的定义格式:

格式:public default 返回值类型 方法名(参数列表){ }

范例:public default void show(){ }

▶ 注意事项

① public可以省略,但是default不能省略。

② 默认方法,实现类是允许重写的,但是需要去掉default关键字。

③ 如果一个类中实现了多个接口,多个接口中存在相同的默认方法,而逻辑不一样,实现类必须强制重写默认方法。

(2)允许定义静态方法

既然接口已经允许方法带有方法体了,也放开静态方法,可以类名调用。

▶ 注意事项

① public可以省略,但是default不能省略。

② 接口中的静态方法,只允许接口名进行调用,不允许实现类通过对象调用。

public class InterfaceTest1 {
    public static void main(String[] args) {
        AInterImpl a = new AInterImpl();
        a.method();
        A.functionn();// 接口中的静态方法,只允许接口名进行调用,不允许实现类通过对象调用
    }
}
interface A {
    default void method() {
        System.out.println("A-------method");
    }
    public static  void functionn() {
        System.out.println("A-------functionn");
    }
}
interface Inter {
    void show();
    void print();
    default void method(){  //public可以省略,default不可省略
        System.out.println("Inter------method");
    }
}
class AInterImpl implements Inter,A {//类中实现多个接口,且多个接口存在相同的默认方法,实现类必须强制重写默认方法
    @Override
    public void show() {
        System.out.println("AInterImpl___show");
    }

    @Override
    public void print() {
        System.out.println("AInterImpl___print");
    }

    @Override
    public void method() {
        Inter.super.method();//可以被实现类重写,要去掉default关键字
    }
}

class BInterImpl implements Inter {
    @Override
    public void show() {
        System.out.println("BInterImpl___show");
    }

    @Override
    public void print() {
        System.out.println("BInterImpl___print");
    }
}

运行结果:

Inter------method
A-------functionn

2.JDK9接口特性

接口中允许定义私有方法

public class InterfaceTest {
    public static void main(String[] args) {

    }
}
interface Inter {
    void method1();
    void method2();

public default void start(){
    System.out.println("start方法执行...");
    //System.out.println("日志记录");
}
public default void end(){
    System.out.println("end方法执行...");
    //System.out.println("日志记录");
}
public default  void log(){
    System.out.println("日志记录");
}
}//两个默认方法里面有一段逻辑是重复的,复用性差,可以将重复的逻辑抽取出一个方法,这个方法不希望被别的类调用,
// 只服务于start和end方法,就私有化将public变成private,也可以是静态的

二、代码块

● 使用{ }括起来的代码块被称为代码块。

(一)局部代码块

位置:方法中的一对大括号。

作用:限定变量的声明周期,提早的释放内存。

(二)构造代码块

位置:类中方法外的一对大括号。

特点:在创建对象,执行构造方法的时候,就会执行构造代码块(构造代码块优先于构造方法执行)。

作用:将多个构造方法中,重复的代码,抽取到构造代码块中,从而提升代码的复用性。

public class blockDemo1 {
    public static void main(String[] args) {
        Student s=new Student();
        Student ss=new Student(10);

    }
}
class Student {
    {
        System.out.println("Student类的构造代码块");
    }
    public Student(){
        System.out.println("空参构造方法......");
    }
    public Student(int num){
        System.out.println("带参构造方法......");
    }
}

运行结果:

Student类的构造代码块
空参构造方法......
Student类的构造代码块
带参构造方法......

(三)静态代码块

位置:类中方法外的一对大括号,需要加入static关键字。

特点:随着类的加载而执行,因为类只加载一次,所以也就只执行一次。

(只要这个类的字节码文件一加载,它就会执行)

作用:对数据进行初始化

(如果将来初始化的数据是一个对象,而且这个对象的初始化很是复杂,就可以借助于静态代码块)

public class blockDemo1 {
    public static void main(String[] args) {
        Student s=new Student();
        Student ss=new Student(10);

    }
}
class Student {
    static{
        System.out.println("static------Student类的静态代码块");
    }
    {
        System.out.println("Student类的构造代码块");
    }
    public Student(){
        System.out.println("空参构造方法......");
    }
    public Student(int num){
        System.out.println("带参构造方法......");
    }
}

运行结果:

static------Student类的静态代码块
Student类的构造代码块
空参构造方法......
Student类的构造代码块
带参构造方法......

三、内部类

● 内部类就是定义在一个类里面的类

class Outer{
    //内部类
    class  Inner{

    }
}

● 内部类创建对象的格式:

格式:外部类名.内部类名  对象名  =  new 外部类对象().new 内部类对象();

e g:  Outer.Inner in =new Outer().new Inner();

public class Innerclass1 {
    public static void main(String[] args) {
        Outer.Inner OI =new Outer().new Inner();
        System.out.println(OI.num);
        OI.show();
    }
}
class Outer{
    class  Inner{
        int num =10;
        public void show(){
            System.out.println("show....");
        }
    }
}

运行结果:

10
show....

(一)成员内部类

● 内部类成员访问细节

        ▶ 内部类中,访问外部类成员:直接访问,包括私有

        ▶ 外部类中,访问内部类成员:需要创建对象访问

public class Innerclass1 {
    public static void main(String[] args) {
        Outer.Inner OI =new Outer().new Inner();
        System.out.println(OI.num);
        OI.show();
    }
}

class Outer{
    private void method(){
        System.out.println("method1...");
        Inner i= new Inner();//外部类访问内部类:创建对象访问
        System.out.println(i.num);
    }

    class  Inner{
        int num =10;

        public void show(){
            System.out.println("show....");
            method();//内部类中访问外部类:直接访问
        }

    }
}

运行结果:

10
show....
method...
10

● 外部类中的成员变量跟内部类中的成员变量重名了,如何区分?

        ▶ 内部类中的成员变量直接用或者this调用

        ▶ 外部类中的成员变量用外部类名.this调用

public class Innerclas2 {
    public static void main(String[] args) {
        MyOuter.MyInner m =new MyOuter().new MyInner();
        m.show();
    }
}
class MyOuter{
    int num = 10;

    class MyInner{
        int num = 20;
        public void show(){
            int num = 30;
            System.out.println(num);//30
            System.out.println(this.num);//20
            System.out.println(MyOuter.this.num);//10
        }

    }
}

运行结果:

30
20
10

(二)静态内部类

● 有static修饰的成员内部类

class Outer{
    //静态内部类
   static  class  Inner{

    }
}

● 静态内部类创建对象的格式

格式:外部类名.内部类名 对象名 = new 外部类名.内部类对象();

eg:Outer.Inner in = new Outer.Inner();

eg:

public class staticinnerclass {
    public static void main(String[] args) {
        Outerclass.innerclass o = new Outerclass.innerclass();
        o.show1();
    }
}

class   Outerclass{

    static class innerclass{

        public static void show1(){
            System.out.println("innerclass1...show1");
        }

    }
}

运行结果;

innerclass1...show1


● 调用非静态show方法,需要创建对象进行访问
    调用静态show方法,直接类名调用

public class staticinnerclass1 {
    public static void main(String[] args) {
        Outerclass1.innerclass1 o = new Outerclass1.innerclass1();
        o.show();//非静态show方法,需要创建对象进行访问
        Outerclass1.innerclass1.show1();//静态show1方法,直接类名调用
    }
}

class   Outerclass1{

    static class innerclass1{
        public void show(){//非静态show方法,需要创建对象进行访问
            System.out.println("innerclass1...show");
        }

        public static void show1(){//静态show方法,直接类名调用
            System.out.println("innerclass1...show1");
        }
    }
}

运行结果:

innerclass1...show
innerclass1...show1

注意事项:静态只能访问静态

(三)局部内部类

● 放在方法、代码块、构造器等执行体中

eg:

public class localclass {
    public static void main(String[] args) {
        A a = new A();
        a.show1();
    }
}

class A{
    public void show1() {//以在方法内部的局部内部类为例

        class B {
            public void method1() {
                System.out.println("innerclass1...show1");
            }
        }
        B b = new B();
        b.method1();
    }
}

运行结果:

innerclass1...show1

(四)匿名内部类

概述:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)

前提:需要存在一个接口或类

格式:new· 类名/接口(){

}

new 类名(){ }:代表继承这个类

new 接口名 (){ }:代表实现这个接口

代码1:

public class niminginnerclass {
    public static void main(String[] args) {
        //问题:方法的形参是接口类型,我们该传入的是什么?
        //回答:传入的是该接口的实现类对象
        useInter(new interImpl());
    }

    public static void useInter(Inter i) {
        i.show();
    }

}

interface Inter {
    void show();
}

class interImpl implements Inter{
    @Override
    public void show() {
        System.out.println("interImpl...show");
    }
}

如果今后再调用一个方法,而方法的形参是接口类型,那么该传入的就是该接口的实现类对象

编写一个类实现接口,重写了show方法,创建了实现类对象传到方法里去
只是为了调用一个参数是接口的方法,就进行了三步操作
但如果用匿名内部类的话其实一步就能解决

ublic class AnonclassTest1 {
    public static void main(String[] args) {
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("匿名内部类.....show");
            }
        });
    }

    public static void useInter(Inter i) {
        i.show();
    }
}

interface Inter1 {
    void show();
}

运行结果:

匿名内部类.....show

结论:

(1)匿名内部类可以使代码变得更简洁,在定义类的时候就对其进行实例化。

(2)匿名内部类可以作为方法的实际参数进行传输。

在调方法的时候,发现方法的参数是接口,那你得给实现类对象,实现类对象有两个选择:要么新泻一个实现类对象,要么给一个匿名内部类,而这两者之间如何选择:

        如果这个接口里面的抽象方法很少,就用匿名内部类;

        反之,抽象方法很多还用匿名内部类,代码就会显得非常臃肿了,所以还是写实现类对象。                

四、Lambda表达式

(一)概述

● Lambda表达式是JDK8开始后的一种新语法形式

● 作用:简化匿名内部类的代码写法

● 简化格式:()- > { }

(匿名内部类被重写方法的形参列表) -> {被重写方法的方法体代码}

代码展示:

public class LambdaTest1 {
    public static void main(String[] args) {
        useInter(new interImpl());

        useInter(new inter() {
            @Override
            public void show() {
                System.out.println("匿名内部类...show");
            }
        });

        useInter(()-> {System.out.println("Lambda表达式...show");});
    }
    public static void useInter(inter in){
        in.show();
    }
}

interface inter {
    void show();
}

class interImpl implements inter{
    @Override
    public void show() {
        System.out.println("interImpl实现类...show");
    }
}

运行结果:

interImpl实现类...show
匿名内部类...show
Lambda表达式...show

注意:

① 并不是所有的匿名内部类都可以用Lambda进行简化的,Lambda表达式只允许操作函数式编程接口。

②函数式编程接口:有且仅有一个抽象方法的接口。

③ 通常会在接口加上一个@FunctionalInterface注解来判断是不是函数式编程接口

(二)Lambda表达式的省略写法

● 参数类型可省略不写。

● 如果只有一个参数,参数类型可以省略,同时()也可以省略。

● 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号。

此时,如果这行代码是return语句,必须省略return不写,同时也必须省略分号不写

eg 1:

public class LambdaTest1 {
    public static void main(String[] args) {
        //匿名内部类
        useShowHandler(new ShowHandler() {
            @Override
            public void show() {
                System.out.println("我是匿名内部类重写后的show方法...");
            }
        });
        //Lambda表达式未省略版
        useShowHandler(()->{System.out.println("我是完整Lambda表达式重写后的show方法...");});
        //Lambda表达式省略版
        useShowHandler(() -> System.out.println("我是省略的Lambda表达式重写后的show方法..."));
    }
    public static void useShowHandler(ShowHandler showHandler) {
        showHandler.show();
    }
}

interface ShowHandler {
    void show();
}

运行结果:

我是匿名内部类重写后的show方法...
我是完整Lambda表达式重写后的show方法...
我是省略的Lambda表达式重写后的show方法...

eg 2:

public class LambdaTest2 {
    public static void main(String[] args) {
        //匿名内部类
        useStringHandler(new StringHandler() {
            @Override
            public void printMessage(String msg) {
                System.out.println("匿名内部类打印:"+msg);
            }
        });
        //Lambda表达式未省略版
        useStringHandler((String msg)->{System.out.println("Lambda表达式打印"+msg);});
        //Lambda表达式省略版
        useStringHandler(msg -> System.out.println("省略的Lambda表达式打印"+msg));
    }
    public static void useStringHandler(StringHandler  stringHandler) {
        stringHandler.printMessage("Hello World");
    }
}

interface StringHandler{
    void printMessage(String msg);
}

运行结果:

匿名内部类打印:Hello World
Lambda表达式打印Hello World
省略的Lambda表达式打印Hello World

eg 3:

import java.util.Random;

public class LambdaTest3 {
    public static void main(String[] args) {
        //匿名内部类
        useRandomNumHandler(new RandomNumHandler() {
            @Override
            public int getNumber() {
               /* Random r = new Random();
                int num = r.nextInt(100) + 1;
                return num;*/
                return new Random().nextInt(100) + 1;
            }
        });
        System.out.println("-------------------------------------");
        //Lambda表达式
        useRandomNumHandler(()->  new Random().nextInt(100) + 1);
    }

    public static void useRandomNumHandler(RandomNumHandler randomNumHandler) {
        int result = randomNumHandler.getNumber();
        System.out.println(result);
    }
}

interface RandomNumHandler {
    int getNumber();
}

运行结果:

14
-------------------------------------
20

eg 4:

public class LambdaTest4 {
    public static void main(String[] args) {
        //匿名内部类
        useCalculato(new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a + b;
            }
        });
        System.out.println("----------------------------");
        //Lambda表达式
        useCalculato((a,b)-> a + b);
    }
    public static void useCalculato(Calculator  calculator) {
        int results = calculator.calc(10, 20);
        System.out.println(results);
    }
}

interface Calculator{
    int calc(int a,int b);
}

运行结果:

30
----------------------------
30

(三)Lambda表达式和匿名内部类的区别

(1)使用限制不同

● 匿名内部类:可以操作类,接口。

● Lambda表达式:只能操作函数或接口。

(2)实现原理不同

● 匿名内部类:编译之后,产生一个单独的.class字节码文件。

● Lambda表达式编译之后,没有一个单独的.class字节码文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值