【java基础】05-内部类和Lambda表达式

1.内部类-成员内部类

通过外部类使用内部类1
通过外部类使用内部类2


概念

  • 一个类定义在另一个类里面,这个里面的类称为内部类,这个外面的类称为外部类
  • 内部类也被称为嵌套类(inner class,nested class),密封类(sealed class)

格式

class Outer { //外部类
    //成员位置 方法外
    class Inner {} //内部类
    
    public void method() {
        //局部位置  方法内
        class Inner2 {}
    }
}

内部类的访问方式一:
通过外部类的方法使用内部类

public class Outer {

    //内部类
   class Inner {
        public void show() {
            System.out.println("show.....");
        }
    }

    //方式一:通过外部类的方法使用
    public void method() {
        //创建内部类对象
        Inner in = new Inner();
        in.show();
    }

}

内部类的访问方式二:

第三方直接创建内部类对象(格式)

 //内部类访问方式二:第三方直接创建内部类对象
        Outer.Inner oi = new Outer().new Inner();
        oi.show();

内部类访问特点:

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象

2.私有成员内部类-静态成员内部类

成员内部类,也属于(成员),既然是成员就可以被一些修饰符所修饰

  • private
    私有成员内部类访问:在自己所在的外部类中创建对象访问。
  • static
    静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
    静态成员内部类中的静态方法:外部类名.内部类名.方法名();

内部类的分类:成员内部类(方法外定义)局部内部类(方法内定义)


成员内部类常见的修饰符
1.private

访问方式2种,少了一种

只能通过内部类的方法访问,第三方无法直接访问private的内部类

作用: 只希望在外部类内部使用,不希望第三方直接创建内部类对象

2.static

访问方式2种,格式变了

// Outer.Inner oi = new Outer().new Inner();//普通成员内部类方式不行
 Outer.Inner oi = new Outer.Inner(); //少创建了一个外部类对象

作用:创建内部类对象更方便,无需创建外部类对象

如果静态成员内部类的成员是静态的,那么连内部类对象也可以不创建

public class Outer {
    //内部类的分类   

   //private int age;

    //成员内部类
//    private class Inner {
//        public void show() {
//            System.out.println("show.....private");
//        }
//    }
    

    static class Inner {
        public void show() {
            System.out.println("show.....static");
        }
    }

    //方式一:通过外部类的方法使用
    public void method() {
        //创建内部类对象
        Inner in = new Inner();
        in.show();
    }
}

public class Demo1 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();

        //第三方直接使用private成员内部类 ,No!!
       // Outer.Inner oi = new Outer().new Inner();

       // Outer.Inner oi = new Outer().new Inner();//普通成员内部类方式不行
        Outer.Inner oi = new Outer.Inner(); //少创建了一个外部类对象
        oi.show();
    }
}

扩展

成员内部类经常用 private 修饰(ArrayList里有)

专门给外部类自己用, 其他类无法创建内部类对象

内部类的使用场景:

1. 有一个类,只想在本类内部使用,不希望其他类直接使用,可以声明为成员内部类,并使用 private 修饰

2. 一个类希望可以直接访问到其他类的 private 成员变量,可以声明为其内部类

3.局部内部类

局部内部类
扩展:

局部内部类访问局部变量,局部变量需要是常量

堆中的对象和局部变量的生命周期不一致

4.匿名内部类

匿名内部类1
匿名内部类2
匿名内部类3
匿名内部类4
好处:
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
那么这种情况下就可以省略掉该类的定义,而改为使用“匿名内部类”。

public class Demo1 {
    public static void main(String[] args) {
        //创建实现类对象
        new InterImpl().show();

        //1.匿名内部类的前提
        //1.有一个接口,抽象类
        //2.格式
        // new 接口名() {重写方法}
        new Inter() {
            @Override
            public void show() {
                System.out.println("匿名内部类实现show....");
            }
        }.show();

        //多态调用
        Inter in = new Inter() {
            @Override
            public void show() {
                System.out.println("匿名内部类实现show....");
            }
        };
        in.show();
        in.show();

        //3.格式的理解
        // 一个实现了接口的实现类对象或继承了父类的子类对象
        //4.好处
        //如果一个实现类,只创建一次对象,就不用专门定义一个类了,可以用匿名内部类
    }
}

interface Inter {
    void show();
}

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

5.匿名内部类的使用场景

匿名内部类使用场景1
匿名内部类使用场景2
接口多态方式实现匿名内部类:

1. 写一个接口 interface Swiming
2. 写一个或多个实现类SwimingImpl,实现接口,重写抽象方法 swim()
3. 在测试类中,写一个方法,方法的参数类型是接口类型 useSwimming(Swiming swimming)
4. 在main方法中,调用方法,传入实现类对象,传入匿名内部类

示例:

public class Demo4 {
    public static void main(String[] args) {
        //传入接口实现类对象
        useSwimming(new SwimmingImpl());

        //传入匿名内部类
        useSwimming(new Swimming() {
            @Override
            public void swim() {
                System.out.println("匿名内部类..想游泳...");
            }
        });
    }

    //使用接口的方法
    public static void useSwimming(Swimming swimming) {
        swimming.swim();
    }

}


interface Swimming {
    void swim();
}

class SwimmingImpl implements Swimming {
    @Override
    public void swim() {
        System.out.println("实现类..想游泳...");
    }
}

使用匿名内部类的优势:

  • 如果实现类对象只用一两次,就不用专门创建一个类了,可以使用匿名内部类
  • 如果实现类对象需要经常使用,最好还是定义一个实现类实现接口,创建实现类对象

匿名内部类要点:

1.何时使用实现类或匿名内部类?
    	//匿名内部类: 1.如果接口实现类只使用1,2次  2.代码比较简单 
        //普通实现类:  1.如果接口实现类需要反复使用 2.代码较复杂    

2. 格式
	new 接口名/抽象类() {重写方法}

3. 格式的理解
		实现类对象/子类对象

6.Lambda初体验和函数式编程思想

Lambda表达式思想
要点:

\1. 函数式编程思想
	数学中的函数是有输入和输出的一套计算方案,简单说,就是拿数据做操作
    例如:使用Excel,公式,求和,演示下

面向对象思想:		
    	 哪个对象去做? 做什么?
函数式编程思想:	
​		更关注做什么,不关注哪个对象去做!		

当要使用一个接口的时候,以前使用实现类对象,再使用匿名内部类,都是局限于面向对象的语法,需要传入一个对象,但其实,方法体才是我们真正要做的事!!!

2. 支持 Lambda 就是函数式编程思想在jdk8中的具体体现之一.
3. Lambda表达式可以简化面向对象的格式

7.Lambda表达式的格式说明和前提条件

Lambda1
Lambda2
Lambda3
要点:

Lambda的标准格式:
	(参数列表) -> {代码}
	例如: (int i) -> {System.out.println(i);}

试试,1. 写一个接口	ShowHandler   void show()
         写个实现类 ShowHandlerImpl 实现接口,重写方法
​	2. 在测试类中,写一个方法,方法的参数类型是接口类型  void useShowHandler(ShowHandler showHandler)3. 在main方法中,调用使用接口的方法,传入实现类对象,匿名内部类
    4.使用Lambda替换匿名内部类 

Lambda使用的前提:
    1. 必须是接口,并且有且仅有一个抽象方法(函数式接口)
    2. 必须有上下文环境

示例:

public class Demo1 {
    public static void main(String[] args) {
//        ​	\1. 写一个接口	ShowHandler   void show()
//        ​	\2. 在测试类中,写一个方法,方法的参数类型是接口类型  void useShowHandler(ShowHandler showHandler)
//        ​	\3. 在main方法中,调用使用接口的方法,传入匿名内部类
//          \4.使用Lambda替换匿名内部类

        useShowHandler(new ShowHandlerImpl());//实现类对象 
		//匿名内部类
        useShowHandler(new ShowHandler() {
            @Override
            public void show() {
                System.out.println("匿名内部类.show....");
            }
        });

        //Lambda表达式 函数式编程思想(简化格式,实现功能)
        useShowHandler(
            () -> {
            System.out.println("Lambda.show....");
        });
    }
    //使用接口的方法
    public static void useShowHandler(ShowHandler handler) {
        handler.show();
    }
}
//接口
interface ShowHandler {
    public abstract void show();
}
//实现类
class ShowHandlerImpl implements ShowHandler {
    @Override
    public void show() {
        System.out.println("实现类.show....");
    }
}

小结:

面向对象思想:
​	强调 哪个对象? 做什么?
函数式编程思想:
​	不关注哪个对象,关注做什么? 方法体就是做什么的!

当要使用一个接口的时候,以前使用实现类对象,再使用匿名内部类,都是局限于面向对象的语法,但其实,方法体才是我们真正要做的事!

方法的参数是接口
1. 可以传入实现类对象
2. 可以传入匿名内部类
3. 可以传入Lambda( 必须是接口(有且仅有一个抽象方法))

8.Lambda的省略格式

Lambda省略规则
Lambda省略规则2

9.匿名内部类和Lambda表达式的区别

匿名内部类和Lambda的区别1
匿名内部类和Lambda的区别2
匿名内部类和Lambda的区别3
Lambda使用前提:

  1. 是一个接口,有且仅有一个抽象方法(函数式接口)

  2. 要有上下文推断

Lambda小结:

lambda格式  (int x,int y) -> {}
Lambda好处  简化匿名内部类(必须是函数式接口:有且仅有一个抽象方法的接口) 
Lambda的使用前提  1.函数式接口(有且仅有一个抽象方法的接口)  2.上下文环境
案例: 接口,抽象方法: 空参,有参,有返回值,有参有返回值
案例步骤:(1.定义接口,  2. 定义一个使用接口的方法,参数类型是接口 3.调用方法,传入匿名内部类或Lambda)
Lambda的省略规则
Lambda与匿名内部类的区别(1.函数式接口 2.原理)

API

1.API-基本使用

API概念

2.API-Math

API-Math
产生1-100之间的int随机数
Math.random();

 // 1- 100
Random r = new Random();
int num = r.nextInt(100) + 1;

// 1-100

```java
int n = (int) (Math.random() * 100) + 1;

3.API-System

System类的常用方法1
System类的常用方法2
System类的常用方法3
System类的常用方法4
要点:
1.简单介绍下,当前时间毫秒值的含义
1970-1-1 08:00:00 到现在过了多少个毫秒

	long now = System.currentTimeMillis();
        System.out.println(now);//1604314106909 当前时间毫秒值

        System.out.println(now / 1000 / 60 / 60 / 24 / 365);//1970年到现在过了多少年
  1. 作用: 统计一段代码的运行时间

  2. 数组复制,索引不要越界

   int[] arr = {1,2,3,4,5};
        int[] arr2 = new int[5];
        System.arraycopy(arr,0,arr2, 0,arr.length);//OK
		System.arraycopy(arr,0,arr2,4,arr.length);//??  索引不要越界
        System.out.println(Arrays.toString(arr2));//打印数组元素

4.Object-toString

  1. Object类是所有类的直接或间接父类
  2. 直接打印一个对象就是打印这个对象的toString方法的返回值
  3. Object类的toString方法得到的是对象的地址值
  4. 我们一般会对toString方法进行重写

要点(idea操作):

1.Object是类层次结构的根类.任何类都直接或间接继承Object类,包括数组 
    
    class Animal {} 
    //class Animal extends Object {} 
    class Cat extends Animal {} 

2.打印一个对象,其实就是打印对象的toString()返回值

    Person p = new Person("jack",19);
    System.out.println(p); //和下面效果一样
    System.out.println(p.toString());//和上面效果一样   

注意:
    //注意: p 和 p.toString()  不是一回事
    // 只是  System.out.println(p); 和 System.out.println(p.toString());效果一样
    // System.out.println(p == p.toString()); //都不是一个类型,不能使用==比较
  

3.Object类的toString()方法:默认返回的是对象的地址值,一般没什么意义,我们一般会重写toString()返回对象成员   变量的字符串形式,使用快捷键  alt + insert自动生成即可  

双击shift,输入Object,可以打开这个类的源码

5.Object-equals

Object重写equals方法
回顾:

==:运算符 
int i = 10;
int j = 10;
System.out.println(i == j);  

String s = new String("hello");
String s2 = new String("hello");
System.out.println( s == s2);// false 

Object类的equals()方法:是比较对象的地址值(意义不大),一般建议子类重写equals方法,比较对象的成员变量值,也就是比较对象的内容. 

Person p = new Person("Jack",19);
Person p2 = new Person("Jack",19); 
System.out.println(p == p2);//

System.out.println(p.equals(p2)); //不重写就调用Object类的equals() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值