Java学习笔记-嵌套类
嵌套类
嵌套类有两种类别:static and non-static,分别对应为静态嵌套类和内部类。
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
其中静态嵌套类只能访问外部类的静态成员,内部类可以访问外部类的任意成员;它们可以被声明为private, public, protected, 或 package private。
- 静态嵌套类实例化方式为: OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
- 内部类实例化方式:OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 即通过外部类实例才能访问内部类。
有两个比较特殊的内部类,分别为局部内部类和匿名类。
局部内部类
- 局部内部类(Local CLasses)可声明在类中任意块(block)中,如方法、for或if块中
- 局部内部类可以访问外部类的成员,若局部内部类声明在静态块中,则可访问外部类的静态成员;若声明在非静态块中,则可访问外部类所有成员;
- 局部内部类可以访问所在块的局部变量,但该局部变量必须声明为final;在JDK8中进行了改进,局部变量可以声明为final或effectively final;
- 其他特性类似于普通内部类
其中effectively final与final局部变量的区别在于,前者可以不显式声明变量为final,只要在整个过程中,该变量不会被修改(编译器默认该情况为final)。具体为什么局部内部类为什么必须引用final变量,可参考
java为什么匿名内部类的参数引用时final? 。大致意思是局部内部类引用局部变量,其实是进行的值引用(或者说是值拷贝)。可以认为避免外部代码块在内部类运行结束前结束,导致局部变量回收而出错。
匿名类
匿名类与局部内部类相似,只是没有命名,并且同时进行声明和实例化。如下:
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
匿名内部类适用于只用一次的情况。其他的特性与局部内部类相同。
Lambda表达式
interface LambdaTest {
int opt(int a , int b);
}
LambdaTest sumTest = (a,b) -> a+b;
第5行即为Lambda表达式声明,其中(a,b)为方法的参数,a+b为方法体,->表示将参数传递给方法体。
- Lambda表达式的方法体中,可以是一个表达式,也可以是代码块。若为表达式,Java运行期会计算表达式,并返回结果;若为代码块,可以添加return语句,将结果返回。
- Lambda表达式其实是一个方法的声明,可以认为Lambda表达式是匿名方法。
- Lambda表达式与局部内部类和匿名类相似,可以访问外部类和外部代码块的变量;但与后两者不同,其不存在变量覆盖的问题,可以认为没有引入新的代码块,其与外部代码块中的局部变量同级。
- 由于第三条,所以在表达式的参数中,不能声明与同级作用域相同的变量名,否则会出现重复定义的异常。
- Lambda表达式是匿名内部类实现形式的一种,其访问的外部变量必须是final或effectively final。
举例如下:
public class Lambda {
private int var = 100;
private String x = "hello";
interface Cal{
int op(int a, int b);
}
interface Print{
void print(String msg);
}
public int operator(int a, int b, Cal cal) {
return cal.op(a, b);
}
public void operator1(String msg, Print print) {
print.print(msg);
}
public void operator2(String x) {
// x = "";
Print print = (msg) -> {
System.out.println("Lambda访问外部变量:");
System.out.println(x);
System.out.println(msg);
System.out.println(Lambda.this.x);
};
print.print(x);
}
public static void main(String[] args) {
Cal add = (a,b) -> {return a+b;};
Cal mul = (a,b) -> a*b;
Lambda lambda = new Lambda();
System.out.println("2+3="+lambda.operator(2, 3, add));
System.out.println("2*3="+lambda.operator(2, 3, mul));
lambda.var = 200;
Print print = (msg) -> {
System.out.println(msg);
System.out.println(lambda.var);
};
lambda.operator1("Hello World", print);
lambda.operator2("Hello Lambda");
}
}
运行结果:
2+3=5
2*3=6
Hello World
200
Lambda访问外部变量:
Hello Lambda
Hello Lambda
hello
其中operator2方法可以验证后三条,如果将24行的注释取消,28行就会报“local variables referenced from a lambda expression must be final or effectively final”的异常。
目标类型(Target Type)
目标类型为外部类方法期望调用的类型,如上例中operator期望调用的目标方法为Cal。Java会根据Lambda表达式所处的语境和上下文信息判断目标类型,并实现调用。
public class TargetType {
interface Cal{
String op();
}
interface Cal1{
int op1();
}
interface Cal2{
void op1();
}
public static String invoke(Cal cal) {
return cal.op();
}
public static void invoke(Cal1 cal1) {
cal1.op1();
}
public static void invoke(Cal2 cal2) {
cal2.op1();
}
public static void main(String[] args) {
invoke(() -> "done");
invoke(() -> 100);
invoke(() -> {return;});
}
}
声明三个接口(Cal Cal1 Cal2),具有相同名称的方法,但他们的返回值不同。另声明了3个invoke方法,分别接收3个类,即期望的目标类型不同。然后进行测试:
main方法中的三个语句都通过编译,并且eclipse提示28行调用目标类型为Cal的invoke,29行调用目标类型为Cal1的invoke,30行调用目标类型为Cal2的invoke,目标类型如下图所示:

(1)如果再添加一句如:invoke(() -> 100.0); 则编译器会报错,Type mismatch: cannot convert from double to String;
(2)如果将Cal接口方法的返回值改为int,则除了28行报错,29行也报错:The method invoke(TargetType.Cal) is ambiguous for the type TargetType,即编译器无法确定调用哪个目标类型。
public interface Runnable {
void run();
}
public interface Callable<V> {
V call();
}
方法声明:
void invoke(Runnable r) {
r.run();
}
<T> T invoke(Callable<T> c) {
return c.call();
}
String s = invoke(() -> "done");
总结:
- 静态嵌套类与内部类区别
- 两类特殊的内部类,局部内部类和匿名内部类;
- 匿名内部类的特殊实现:Lambda表达式,可认为匿名方法的实现;
- Lambda表达式会根据上下文环境确定目标类型
参考:
Java学习笔记-嵌套类的更多相关文章
- Java学习笔记——File类之文件管理和读写操作、下载图片
Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...
- Java学习笔记之---类和对象
Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态 例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...
- Java7编程 高级进阶学习笔记--嵌套类
定义: 在一个类中定义的类叫做嵌套类. 作用: 1.允许对相关类进行逻辑分组 2.增强了代码的封装性 3.使代码具有更强的可读性和维护性 使用方式: package com.cmz.baseTest; ...
- Java学习笔记-File类的基本方法
要渐渐养成写博客的习惯-----> 前段时间看Mars的java中的I/O流没怎么懂,发现I/O流好难啊.今天重新看一遍其他教学,还有书籍,做些笔记,记录下每天的学习生活. File类的一些方法 ...
- Java学习笔记 04 类和对象
一.类和对象的概念 类 >>具有相同属性和行为的一类实体 对象 >>实物存在的实体.通常会将对象划分为两个部分,即静态部分和动态部分.静态部分指的是不能动的部分,被称为属性,任 ...
- Java学习笔记——SequenceInputStream类合并文件的综合举例分析
SequenceInputStream 介绍 SequenceInputStream 类表示其他输入流的逻辑串联,即文件的合并. 它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾, ...
- 0018 Java学习笔记-面向对象-类的基本要素
类与对象 大街上一个个的人,就是一个个对象 类是对一群对象的抽象,比如人都有性别.年龄.姓名,都会吃饭.睡觉等.姓名性别可以抽象为变量,吃饭睡觉可以抽象为方法,像下面一样定义个类来形容人 public ...
- Java学习笔记7---父类构造方法有无参数对子类的影响
子类不继承父类的构造方法,但父类的构造方法对子类构造方法的创建有影响.具体来说就是: ①.当父类没有无参构造方法时,子类也不能有无参构造方法:且必须在子类构造方法中显式以super(参数)的形式调用父 ...
- Java学习笔记之——类与对象
1.参数的传递方式 1)值传递 2)引用传递 2.类和对象: (1)类的定义: public class 类名{ 类型 属性1: 类型 属性2: ……… public 返回值类型 方法名1(形参){ ...
随机推荐
- 数据结构与算法(C/C++版)【串】
第四章<串.数组> (一)串 数据结构中提到的串,即字符串,由 n 个字符组成的一个整体( n >= 0 ).这 n 个字符可以由字母.数字或者其他字符组成.例如,S = &qu ...
- 【luogu P1396】营救
https://www.luogu.org/problem/show?pid=1396 弱化版的货车运输,用并查集维护连通块,将边按权值升序排序后依次插入直到两点连通,最后插入的边的权值就是最小的拥挤 ...
- 关于Mysql下使用Dapper QueryFirstOrDefault的问题
1.环境 MySql:5.7.20 Dapper:1.50.2 .Net:4.5 2.遇到的问题 在开发中我发现,使用Dapper查询数据时,第一次查询正确,第二次查询就差不出来,或者直接修改数据库后 ...
- VMware---添加esxi主机的实验
实验环境:window_server_2012_r2_64 SQLServer2012SP1-FullSlipstream-CHS-x64 虚机配置: 关于windows server2012 和 ...
- 对deep learning的第一周调研
下面仅是我的个人认识,说得不正确请轻拍. (眼下,我仅仅看了一些deep learning 的review和TOM Mitchell的书<machine learning>中的神经网络一章 ...
- Linux已经全然统治了这个世界:反对开源社区愚不可及
原文来自:http://readwrite.jp/archives/9977 不管一个企业多强大,它都不存在和开源社区抗衡的实力 十年前.Unix占有最快的计算机世界排名前10位的五席,以及超级计算机 ...
- Python 项目实践一(外星人入侵)第一篇
python断断续续的学了一段实践,基础课程终于看完了,现在跟着做三个小项目,第一个是外星人入侵的小游戏: 一 Pygame pygame 是一组功能强大而有趣的模块,可用于管理图形,动画乃至声音,让 ...
- 【SqlServer系列】聚合函数
1 概述 本篇文章简要回顾SQL Server 聚合函数,MAX,MIN,SUM,AVG,SUM,CHECKSUM_EGG,COUNT,STDEV,STDEVP,VAR,VARP. 2 具体 ...
- 自学WPF之Binding(二)
没有Source的Binding,使用ContentText作为Binding源: 上一篇是把CLR类型对象当作指定为Binding的Source,两种方法:一是把对象赋值给Binding.Sourc ...
- 理解Vue中的Render渲染函数
理解Vue中的Render渲染函数 VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数.比如如下我想要实现 ...