一、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字节码文件。
1366

被折叠的 条评论
为什么被折叠?



