内部类和JDK8新特性
1.内部类
类中嵌套的类,当我们需要使用一个类描述信息,并且此类没有必要被外部其他类使用,我们可以定义为内部类。
1.1普通内部类
1.在类的内部定义,与实例变量、实例方法同级别的类。(位置)
2.外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。(创建对象)
3.当外部类、内部类存在重名属性时,会优先访问内部类属性。(访问属性)
Outer.this.a访问外部类成员
4.成员内部类不能定义静态成员。(非静态不能有静态呀!!!)(规则)
Outer.Inner inner = new Outer().new Inner();
/**
* 普通内部类
*/
public class Test1 {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.a);
outer.m1();
Outer.m2();
Outer.Inner inner = new Outer().new Inner();
inner.innerM1();
}
}
class Outer{
int a = 20;
public void m1(){
System.out.println("外部类普通方法m1");
}
public static void m2(){
System.out.println("外部类静态方法m2");
}
class Inner{
private int a = 100;
private int b = 200;
public void innerM1(){
System.out.println(a);
System.out.println(Outer.this.a);
System.out.println("内部类的普通方法m1");
}
//普通内部类不能定义静态方法
/* public static void innerM2(){
System.out.println("内部类的静态方法m2");
}*/
}
}
1.2静态内部类
1.不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
2.只能直接访问外部类的静态成员(实例成员,即其他成员变量,属性等需实例化外部类对象)。
Outer.Inner inner = new Outer.Inner();
/**
* 静态内部类
*/
public class Test1 {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
System.out.println(inner.c);
inner.innerM1();
Outer.Inner.m2();//内部类的静态方法,通过类名访问
Outer.m2();//外部类的静态方法
}
}
class Outer{
public int a = 20;
public static int b = 100;
public void m1(){
System.out.println("外部类普通方法m1");
}
public static void m2(){
System.out.println("外部类静态方法m2");
}
static class Inner{
public int c = 30;
public static int d = 300;
public void innerM1(){
//System.out.println(a);不能直接访问非静态的内容
System.out.println(b);
m2();
//m1();不能直接访问非静态的内容
System.out.println("内部类的m1方法");
}
public static void m2(){
System.out.println("内部类的m2静态方法");
}
}
}
1.3局部内部类
1.特征与普通外部类基本相似
2.定义在外部类方法中,作用范围和创建对象范围仅限于当前方法
3.局部内部类访问外部类当前方法中的局部变量时,变量必须修饰为final,即使不写,内部类也会默认其被final修饰,即外部类局部变量只可读不可写
4.限制类的使用范围
/**
* 局部内部类
*/
public class Test1 {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.a);
outer.m1();
outer.m2();
}
}
class Outer{
int a = 20;
public void m1(){
System.out.println("外部类的普通方法m1");
int num = 100;
class Inner{
private int b = 2;
public void innerM1(){
// num++; 不能对外部类中普通方法局部变量值做改变
System.out.println(num);
System.out.println("局部内部类的m1");
}
//不能定义静态方法
/*public static void m2(){
System.out.println("局部内部类中的m2");
}*/
}
Inner inner = new Inner();
System.out.println("局部内部类中的属性b:" + inner.b);
}
public static void m2() {
System.out.println("外部类的静态方法m2");
}
}
1.4匿名内部类
1.必须实现一个接口或者继承一个抽象类
2.匿名内部类不能创建对象,只能使用一次
3.优点:减少子类的编写
4.缺点:阅读性较差
5.通常用于接口或者抽象类中只有一个抽象方法的情况
/**
* 匿名内部类 没有名字的内部类
*/
public class Test1 {
public static void main(String[] args) {
Info info = new Info() {
@Override
public void print() {
System.out.println("通过匿名内部类的方式实现接口");
}
@Override
public void m2() {
System.out.println("m1方法");
}
@Override
public void m1() {
System.out.println("m2方法");
}
};
info.print();
A a = new A(){
@Override
public void m1() {
System.out.println("通过匿名内部类的方式实现抽象类");
}
};
a.m1();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程的内容");
}
},"线程A").start();;
//t1.start();
}
}
interface Info{
void print();
void m1();
void m2();
}
abstract class A{
public abstract void m1();
}
2.JDK8新特性
JDK8新特性
1.接口中可以使用default关键字书写普通方法
2.接口中也可以写静态方法
3.Lambda表达式解决匿名内部类代码阅读性差的问题
4.方法引用
5.stream函数式编程
2.1接口相关
JDK8中
1.接口可以使用default关键字书写普通方法(给子类使用)
2.可以书写静态方法(通过接口名+.访问)
public interface A {
public default void m1() {
System.out.println("普通方法,给子类使用");
}
public static void m2() {
System.out.println("静态方法");
}
public static void main(String[] args) {
A.m2();
}
}
2.2Lambda表达式
Lambda表达式属于函数式编程,可以解决匿名内部类阅读性差的问题,但是要求实现Lambda表达式必须是只有一个抽象方法的接口,但并不是只能有一个方法(default,static关键字修饰的,不是必须实现的,所以无影响)我们可以使用@FunctionalInterface注解来约束接口。https://www.cnblogs.com/haixiang/p/11029639.html
/**
* 匿名内部类缺点:代码阅读性差
* 可以使用JDK8提供的新特性解决这些问题
* Lambda表达式属于函数式编程的体现 一些计算机语言就是函数式的语言 比如Haskell
* @author asus
*/
public class Test1 {
public static void main(String[] args) {
A a = new A(){
@Override
public void print() {
System.out.println("匿名内部类实现方式");
}
};
a.print();
// 使用Lambda表达式的方式实现同样的效果
// 使用lambda表达式书写更为简洁 但是不能具体制定重写的是哪个方法
// 所以要求接口只能有一个抽象方法,只能适用于接口
// () - > 这个是固定书写格式
A a1 = ()->System.out.println("lambda表达式方式实现");
a1.print();
//有参数, 类型写不写无所谓
B b = (bb)->System.out.println(bb);
b.print("hello word");
//有返回值,return必须不写
C c = (numa,numb)-> numa + numb;
System.out.println(c.print("a", 20));
//写多条语句
D d =(number1,number2)->{
String string = "hrllo";
return string+number1+number2;
};
System.out.println(d.print(1, 1));
// E e = () -> "hello world"; 抽象类不能使用lambda表达式
}
}
interface D{
String print(int a, int b);
}
//与@override类似,检查
@FunctionalInterface
interface A{
void print();
//void m1();
}
interface B{
void print(String a);
}
interface C{
String print(String a,int b);
}
2.3方法引用
方法引用相当于代码的重用,表示通过Lambda表达式的方式引用某个方法的方法体,可以引用构造方法,普通方法,静态方法。
/**
* 方法引用:把方法体拿来使用,方法引用也是Lambda表达式的体现
* 构造方式引用
* 普通方法
* 静态方法
*/
public class Test1 {
public static void main(String[] args) {
//::表示方法引用
//构造方法引用
Info info = Book :: new;
info.print();
System.out.println(info.getClass().getName());
Info info1 = () ->System.out.println("This is a book");
info1.print();
String flag = String.valueOf(false);
System.out.println(flag.length());
//静态方法引用,,引用的是静态valueof方法,不要写括号
//通过类名String引用,与普通方法引用不同
Message<String,Boolean> ms = String::valueOf;
System.out.println(ms.getStr(true));
String str = "abcd**";
System.out.println(str.startsWith("a"));
//普通方法引用,通过对象名引用
TestStartsWith<Boolean,String> ts = str ::startsWith;
System.out.println(ts.test("*"));
System.out.println("*****************");
PrintHello ph = System.out::println;
ph.print("hello word");
testHelloWord thw = String::valueOf;
System.out.println(thw.print(123));
}
}
interface testHelloWord{
String print(int a);
}
@FunctionalInterface
interface PrintHello{
void print(String str);
}
@FunctionalInterface
interface TestStartsWith<R,P>{
R test(P p);
}
interface Info{
void print();
}
class Book{
public Book(){
System.out.println("这是一本书《钢铁是怎样炼成的》");
}
}
interface Message<R,P>{
R getStr(P p);
}
2.4JDK提供的函数式接口
java.util.function这个包中全部是函数式接口
这个接口大致分为四类
功能型接口 Function 有进有出
消费型接口 Consumer 只进不出
供给型接口 Supplier 只出不进
断言型接口 Predicate
/**
* JDK给我们提供了一个包
* java.util.function 这个包中全部是函数式接口
* 这个接口大致分为四类
* 功能型接口 Function 有进有出
* 消费型接口 Consumer 只进不出
* 供给型接口 Supplier 只出不进
* 断言型接口 Predicate
*/
public class Test2 {
public static void main(String[] args) {
// 引用String类valueOf方法
Function<Integer, String> fun = String :: valueOf;
System.out.println(fun.apply(23566).length());
Consumer<String> con = System.out :: println;
con.accept("hello word");
String str = "abcd";
Supplier<Integer> sup = str :: length;
System.out.println("字符串长度" + sup.get());
// 利用断言接口判断字符串是否以**开头或者结尾
Predicate<String> pre = str :: startsWith;
System.out.println(pre.test("a"));
}
}