由于水平有限,这里目前只讲我理解到的,内容应该够平时开发和看懂一般代码的水平(欢迎大家补充)
定义在普通类中的类即为内部类,该内部类的访问控制可以为public protected default private(普通的类只能使用public。default),内部类可以使用 static 、final
目前认为普通的内部类一般用不着,多半做选择题可以去了解,之后再文末进行补充
class Outer{ int a; void method(){ XXXX... } //内部类 这里的修饰符可以为 public protected default private static final private class Inner{ int x; int function(){ XXX... } } }
这里重点看一下private修饰的内部类。举例:在集合类中,我们使用迭代器(要获取一个迭代器对象)去遍历元素。在ArrayList这个类中有一个私有内部类Itr,这个类实现了迭代器Iterator接口,重写了该接口的方法。
// 获取迭代器对象 Iterator it = list.iterator(); // 这里是ArrayList这个类给我提供了这个迭代器对象,对我们来说是透明的 // 我们只需用这个对象去遍历集合即可 while(it.hasNext()){ sout(it.next()); }
这个it对象其实是ArrayList中的私有内部类Itr的实例对象,在这个Itr类中,实现了遍历元素的方法,在ArrayList类中也提供了生成这个迭代器对象的方法iterator(),这些都是对我们隐藏的,一方面使开发者不用关心底层实现,
只需要调用方法就可以完成自己想完成的业务功能,而不用自己去实现这些复杂的功能来辅助自己完成业务;另一方面,也算是体现了封装性,这个内部类为私有的,自为该类提供服务,特有的专属于这个类的一些方法。
因为Iterator是一个接口,它包含了遍历集合的相关抽象方法,由于不同集合底层的数据结构不相同,所以实现这些方法的方式也是不相同的。因此在不同的集合的实现类中专门定义一个用于实现该接口的私有内部类是很
符合逻辑的,是遵循了封装性,耦合,内聚这些设计思路的。
用途之一:创建一个匿名的实现了某个接口的实例对象,通过该对象实现的方法可以完成特定的功能,可以通过对接口不同的实现代码来完成不同的功能规则
匿名内部类写法:new 接口名(){@override xxx(){}},
一般使用在需要自定义规则的类(eg:java提供的数据结构)中,比如排序规则,构造方法TreeSet<>(new Comparator<>(){@override xxx(){}});
使用在工具类中,传入规则 比如Collections.sort(list,new Comparator<>(){@override xxx(){}});
在策略模式中也会使用到,不同策略就是不同的规则
/** * 一般用来返回某个接口实现类的实例对象,目的是使用该接口中被实现的方法来处理一些规则 * 因为有接口所以功能规则更换比较灵活 * * 掌握1,4,5 */ public class InnerClassTest { public static void main(String[] args) { } //方法1.使用的不是局部内部类,自己在外部定义一个实现接口的类,在方法中返回这个类的对象 public static Comparable getComparator1(){ Comparable c = new MyComparator(); return c; } //方法2,使用局部内部类(在方法中定义的类) 不推荐使用,被优化成了4,不用声明类,和引用 public static Comparable getComparator2(){ class MyComparator implements Comparable{ @Override public int compareTo(Object o) { return 0; } } Comparable c = new MyComparator(); return c; } //3.匿名内部类 不推荐这样写,使用4,不用声明引用 public static Comparable getComparator3(){ Comparable c = new Comparable() { @Override public int compareTo(Object o) { return 0; } }; return c; } //4.匿名内部类加匿名对象(这里是IDEA推荐的写法) public static Comparable getComparator4(){ return new Comparable() { @Override public int compareTo(Object o) { return 0; } }; } //5.在构造方法中传入,这里才是必须要会用的 TreeSet<String> set = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return 0; } }); // 使用lambda表达式 static TreeSet<String> set1 = new TreeSet<>((o1, o2) -> o1.compareTo(o2)); public static void method(){ Collections.sort(new ArrayList<String>(set1),(o1, o2) -> o1.compareTo(o2)); } } // 方法一,这个在(TreeSet,TreeMap)自定义类型比较规则单一的时候适合使用这中方法 class MyComparator implements Comparable{ @Override public int compareTo(Object o) { return 0; } }
lambda表达式是对二中5这种类型的匿名内部类的改进,不用搞一大堆代码,一两行完事;不过这里的接口要为函数式接口(接口中只有一个抽象方法没有实现),
说白了就是匿名内部类的另一种形式,
写法:(x, y) -> Integer.compare(x.length(), y.length()) (参数列表。。。)-> XXXX 实现方法的语句
如果只有一个参数,可以不写括号,如果实现只有一个条语句可以不用写return , 如果函数实现有多条语句,需要讲语句放入{ }
public class LambdaTest { public static void main(String[] args) { List<Employee> list = new ArrayList<>(); list.add(new Employee(12,"e")); list.add(new Employee(42,"g")); list.add(new Employee(52,"a")); list.add(new Employee(12,"c")); list.add(new Employee(12,"d")); list.add(new Employee(12,"e")); System.out.println(list); System.out.println("============使用匿名内部类的方式使:元素按年龄升序,姓名升序=========="); Collections.sort(list, new Comparator<Employee>() { @Override //年龄升序,姓名升序 public int compare(Employee o1, Employee o2) { return o1.getAge()-o2.getAge()==0?o1.getName().compareTo(o2.getName()):o1.getAge()-o2.getAge(); } }); System.out.println(list); System.out.println("==============使用lambda表达式的方式使:元素按年龄降序序,姓名升序======================="); Collections.sort(list,(o1,o2)->o1.getAge()-o2.getAge()==0?o1.getName().compareTo(o2.getName()):o2.getAge()-o1.getAge()); System.out.println(list); } } class Employee{ private int age; private String name; // 省略。。。。 } }
进阶:自己定义类似Comparator的接口,来练习(E:\javaProject\javaSE\rongqi\src\lambdaexer)
四、选择题要关注的点(重要的是能看懂代码结构,各个类,对象之间的联系。相关知识点理解了,并且记得牢)
五、leetcode
692.前K个高频词 https://leetcode-cn.com/problems/top-k-frequent-words/
179.最大数 https://leetcode-cn.com/problems/largest-number/