【05-面向对象(下)】
|
基本数据类型的包装类
•八大数据类型的包装类分别为:Byte、Short、Integer、Long、Character、 Float、Double、Boolean。 把基本数据类型变量包装类实例是通过对应包装类的构造器来实现的,不仅如此,8个包装类中除了 Character之外,还可以通过传入一个字符串参数来构建包装类对象。
•如果希望获得包装类对象中包装的基本类型变量,则可以使用包装类提供的XxxValue()实例方法。
自动装箱与自动拆箱
•JDk还提供了自动装箱和自动拆箱。自动装箱就是把一个基本类型的变量直接赋给对应的包装类变量,自动拆箱 则与之相反。
•包装类还可以实现基本类型变量和字符串之间的转换,除了Character之外的所有包装类都提供了一个 parseXxx(String s)静态方法。
•如果将基本类型转换为这符串,只需在后面加+ “”进行连接运算。 Java 7对包装类的增强
•Java 7为所有包装类增加一个新方法: compare(x , y)的方法。该方法用于比较两个包装类实例,当x>y, 返回大于0的数;当x==y,返回0;否则返回小于0的数。
对象的方法
•打印对象和toString方法:toString方法是系统将会输出该对象的“自我描述”信息,用以告诉外界对象具有的状 态信息。
•Object 类提供的toString方法总是返回该对象实现类的类名 + @ +hashCode值。
•==和equals比较运算符:==要求两个引用变量指向同一个对象才会返回true。equals方法则允许用户提供自 定义的相等规则。
•Object类提供的equals方法判断两个对象相等的标准与==完全相同。因此开发者通常需要重写equals方法。
类成员
•在java类里只能包含Field,方法,构造器,初始化块,内部类(接口、枚举)等5种成员。 用static修饰的类成员属 于类成员,类Field既可通过类来访问,也可以通过类的对象来访问。当通过对象来访问类属性时,系统会在底 层转换为通过该类来访问类 属性。
类成员规则
•类成员并不是属于实例,它是属于类本身的。只要类存在,类成员就存在。 •即使通过null对象来访问类成员,程序也不会引发NullPointerException。 类成员不能访问实例成员。
单例类
•如果一个类始终只能创建一个对象,称为单例类。须符合以下几个条件: –1.我们把该类的构造器使用Private修饰,从而把该 类的所有构造器隐藏起来。 –2.则需要提供一个public方法作为该类的访问点,用于创建该类的对象,且必须使用static修饰 –3.该类还必须缓存已经创建的对象,必须用static修饰
final变量
•final修饰变量时,表示该变量一旦获得 初始值之后就不可被改变。 •final既可修饰成员变量,也可以修饰局部变量。 final修饰成员变量
•成员变量是随类的初始化或对象初始化而初始化的。final修饰的成员变量必须由程序员指定初始值。 •对于类属性而言,要么在静态初始化中初始化,要么在声明该属性时初始化。 •对于实例属性,要么在普通初始化块中指定初始值。要么在定义时、或构造器中指定初始值。 final修饰局部变量
•使用final修饰局部变量时既可以在定义时指定默认值,也可以不指定默认值。 •给局部变量赋初始值,只能一次,不能重复。 final修饰基本类型和引用类型
•当使用final修饰基本数据类型时,不能对其重新赋值,不能被改变。
•但对引用类型的变量而言,它仅仅保存的是一个引用,final只能保证他的地址不变,但不能保证对象,所以引用 类型完全可以改变他的对象。
可执行“宏替换”的final变量
•对一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足3个条件,这个final变量就 不再是一个变量,而是相当于一个直接量。
–使用final修饰符修饰; –在定义该final变量时指定了初始值; –该初始值可以在编译时就被确定下来。
final方法
•final方法 •final 修饰的方法不可以被重写。 •final 修饰的方法仅仅是不能重写,但它完全可以被重载。
•final 修饰的类不可以被继承
不可变的类
•不可变的类要满足以下几个条件: –1.使用private和final修饰符来修饰该类的属性 –2.提供带参数的构造器,用于根据传入参数来初始化类里的属性 –3.仅为该类的属性提供getter方法,不要为该类的属性提供setter方法,因为普通方法无法修改final修饰的 属性 –4.如有必要,重写Object类中hashCode 和equals •缓存实例的不可变类:如果程序经常需要使用不可变类的实例,则可对实例进行缓存。
抽象方法和抽象类
•抽象方法和类都必须使用abstract来修饰,有抽象方法的类只能定义成抽象类,抽象里也可以没有抽象方法。
• 抽象类不能被实例化,可以通过其子类给他赋值,普通类里有的抽象里也有,定义抽象方法只需在普通方法上增 加abstract修饰符,并把普通方法的方法体(也就是方法后花括号括起来的部分)全部去掉,并在方法后增加分号 即可。
抽象类的特征
•抽象类的特征:有得有失,得到了新能力,可以拥有抽象方法;失去了创建对象的能力。 抽象类的作用
•抽象类代表了一种未完成的类设计,它体现的是一种模板。 •抽象类与模板模式。 接口的概念
•接口定义的是多个类共同的行为规范,这些行为是与外部交流的通道,这就意味着接口里通常是定义一组公用的 方法。
•接口体现了规范与实现分离的设计。
接口的定义
•和类定义不同,定义接口不再用class关键字,而是使用interface关键字。语法如下: •[修饰符] interface接口名 extends 父接口1,父接口2 ... •{ • 零个到多个常量定义... • 零个到多个抽象方法定义... • 零个到多个内部类、接口、枚举定义... • 零个到多个默认方法或类方法定义... •}
接口里的成分
•在定义接口时,接口里可以包含成员变量(只能是常量),方法(只能是抽象实例方法、类方法或默认方法),内 部类(包括内部接口、枚举类 –常量都是:public static final修饰 –方法都是:public abstract 修饰 –内部的类:public static
接口的继承
•接口的继承和类继承不一样,接口完全支持多继承,子接口扩展某个父接口将会获得父接口的所有抽象方法,常 量属性,内部类和枚举类定义。
使用接口
•接口可以用于声明引用类型的变量,但接口不能用于创建实例。 •当使用接口来声明引用类型的变量时,这个引用类型的变量必须引用到其实现类的对象。 •一个类可以实现一个或多个接口,继承使用extends关键字,实现接口则使用implements关键字。
实现接口
•一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽 象方法);
•否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。
接口和抽象类的相似性
•接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。 •接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
接口与抽象类的区别
•接口里只能包含抽象方法,不同包含已经提供实现的方法;抽象类则完全可以包含普通方法。 •接口里不能定义静态方法;抽象类里可以定义静态方法。 •接口里只能定义静态常量属性,不能定义普通属性;抽象类里则既可以定义普通属性,也可以定义静态常量属 性。 •接口不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而让其子类调用这些构 造器来完成属于抽象类的初始化操作。 •接口里不能包含初始化块,但抽象类则完全可以包含初始化块。 •一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补 Java单继承的不足。
面向接口编程
•接口体现了规范与实现分离的原则。充分利用接口可以很好地提高系统的可扩展性和可维护性。 •接口与简单工厂模式、命令模式等。
内部类
•我们把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,有的也叫嵌套类,包含内 部类的类也被称为外部类有的也叫宿住类。 •内部类提供了更好的封装,内部类成员可以直接访问外部类的私有数据,因为内部类被当成其他外部类成员。 •匿名内部类适合用于创建那些仅需要一次使用的类。
非静态内部类
•定义内部类非常简单,只要把一个类放在另一个类内部定义即可。
•当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在该 名字的局部变量,就使用该变量,如果不存在,则到该方法所在的内部类中查找是否存在该名字的属性,如果存在 则使用该属性。
•总之,第一步先找局部变量,第二步,内部类的属性,第三步。外部类的属性。
本文原创作者:pipi-changing 本文原创出处:http://www.cnblogs.com/pipi-changing/
静态内部类
•如果用static修饰一个内部类,称为静态内部类。
•静态内部类可以包含静态成员,也可以包含非静态成员。所以静态内部类不能访问外部类的实例成员,只能访问 外部类的类成员。
•静态内部类的对象寄存在外部类里,非静态内部类的对象寄存在外部类实例里
使用内部类
•1.在外部类内部使用内部类-不要在外部类的静态成员中使用非静态内部类,因为静态成员不能访问非静态成 员。
• 2.在外部类以外使用非静态内部类。 –private 修饰的内部类只能在外部类内部使用。 –在外部类以外的地方使用内部类,内部类完整的类名应该OuterClass.InnerClass. –在外部类以外的地方使用非静态内部类创建对象的语法如下:OuterInstance.new InnerConstructor() –在外部类以外的地方使用静态内部类创建对象的语法如下:new OuterClass.InnerConstructer(); 局部内部类 •如果把一个内部类放在方法里定义,这就是局部内部类,仅仅在这个方法里有效。 •局部内部类不能在外部类以外的地方使用,那么局部内部类也不能使用访问控制符和static修饰
匿名内部类 •匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下: •new 父类构造器(实例列表) |实现接口) •{ • //匿名内部类的 类体部分 •} •匿名内部类不能是抽象类,匿名内部类不能定义构造器。
Lambda表达式入门 •Lambda表达式主要作用就是代替匿名内部类的繁琐语法。它由三部分组成: –形参列表。形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略。 –箭头(->),必须通过英文等号和大于符号组成。 –代码块。如果代码块只有包含一条语句,Lambda表达式允许省略代码块的花括号,如果省略了代码块的花括 号,这条语句不要用花括号表示语句结束。Lambda代码块只有一条return语句,甚至可以省略return关键字。 Lambda表达式需要返回值,而它的代码块中仅有一条省略了return的语句,Lambda表达式会自动返回这条语句的 值。
Lambda表达式与函数式接口
•如果采用匿名内部类语法来创建函数式接口的实例,只要实现一个抽象方法即可,在这种情况下即可采用 Lambda表达式来创建对象,该表达式创建出来的对象的目标类型就是这个函数式接口。
•Lambda表达式有如下两个限制: –Lambda表达式的目标类型必须是明确的函数式接口。 –Lambda表达式只能为函数式接口创建对象。Lambda表达式只能实现一个方法,因此它只能为只有一个抽 象方法的接口(函数式接口)创建对象。
•为了保证Lambda表达式的目标类型是一个明确的函数式接口,可以有如下三种常见方式: –将Lambda表达式赋值给函数式接口类型的变量。 –将Lambda表达式作为函数式接口类型的参数传给某个方法。 –使用函数式接口对Lambda表达式进行强制类型转换。 方法引用与构造器引用
Lambda表达式与匿名内部类
•Lambda表达式与匿名内部类存在如下相同点: –Lambda表达式与匿名内部类一样,都可以直接访问“effectively final”的局部变量,以及外部类的成员变 量(包括实例变量和类变量)。
–Lambda表达式创建的对象与匿名内部类生成的对象一样, 都可以直接调用从接口继承得到的默认方法。
•Lambda表达式与匿名内部类主要存在如下区别: –匿名内部类可以为任意接口创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方 法即可。但Lambda表达式只能为函数式接口创建实例。
–匿名内部类可以为抽象类、甚至普通类创建实例,但Lambda表达式只能为函数式接口创建实例。
–匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式的代码块不允许调 用接口中定义的默认方法。
手动实现枚举类
•可以采用如下设计方式: –通过private将构造器隐藏起来。 –把这个类的所有可能实例都使用public static final属性来保存。 –如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配实例。
JDK 5新增的枚举支持
•J2SE1.5新增了一个enum关键字,用以定义枚举类。正如前面看到,枚举类是一种特殊的类,它一样可以有自 己的方法和属性,可以实现一个或者多个接口,也可以定义自己的构造器。一个Java源文件中最多只能定义一个 public访问权限的枚举类,且该Java源文件也必须和该枚举类的类名相同。
枚举类
•枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是继承Object 类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang. Comparable两个接口。
•枚举类的构造器只能使用private访问控制符,如果省略了其构造器的访问控制符,则默认使用private修饰;如 果强制指定访问控制符,则只能指定private修饰符。
•枚举类的所有实例必须在枚举类中显式列出,否则这个枚举类将永远都不能产生实例。列出这些实例时系统会自 动添加public static final修饰,无需程序员显式添加。
•所有枚举类都提供了一个values方法,该方法可以很方便地遍历所有的枚举值。
枚举类的属性、方法和构造器
•枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以使用属性和方法。
•枚举类通常应该设计成不可变类,也就说它的属性值不应该允许改变,这样会更安全,而且代码更加简洁。为 此,我们应该将枚举类的属性都使用private final 修饰。
•一旦为枚举类显式定义了带参数的构造器,则列出枚举值时也必须对应地传入参数。
实现接口的枚举类
•枚举类也可以实现一个或多个接口。与普通类实现一个或多个接口完全一样,枚举类实现一个或多个接口时,也 需要实现该接口所包含的方法。
•如果需要每个枚举值在调用同一个方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个 枚举值提供不同的实现方式,从而让不同枚举值调用同一个方法时具有不同的行为方式。
包含抽象方法的枚举类
•可以在枚举类里定义一个抽象方法,然后把这个抽象方法交给各枚举值去实现即可。
•枚举类里定义抽象方法时无需显式使用abstract关键字将枚举类定义成抽象类,但因为枚举类需要显式创建枚举 值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则将出现编译错误。
垃圾回收机制
•垃圾回收机制只负责回收堆内存中对象,不会回收任何任何物理资源(例如数据库连接,网络IO等资源)。
•程序无法精确控制垃圾回收的运行,垃圾回收会在合适时候进行垃圾回收。当对象永久性地失去引用后,系统就 会在合适时候回收它所占的内存。
•垃圾回收机制回收任何对象之前,总会先调用它的finalize方法,该方法可能使该对象重新复活(让一个引用变量 重新引用该对象),从而导致垃圾回收机制取消回收
对象在内存中的状态
•激活状态:当一个对象被创建后,有一个以上的引用变量引用它。则这个对象在程序中处于激活状态,程序可通 过引用变量来调用该对象的属性和方法。
•去活状态:如果程序中某个对象不再有任何引用变量引用它,它就进入了去活状态。在这个状态下,系统的垃圾 回收机制准备回收该对象所占用的内存,在回收该对象之前,系统会调用所有去活状态对象的finalize方法进行资 源清理,如果系统在调用finalize方法重新让一个引用变量引用该对象,则这个对象会再次变为激活状态;否则该 对象将进入死亡状态。
•死亡状态:当对象与所有引用变量的关联都被切断,且系统会调用所有对象的finalize方法依然没有使该对象变成 激活状态,那这个对象将永久性地失去引用,最后变成死亡状态。只有当一个对象处于死亡状态时,系统才会真正 回收该对象所占有的资源。
强制垃圾回收
•强制系统垃圾回收有如下两个方法: –调用System类的gc()静态方法:System.gc() –调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()
finalize方法
•finalize方法有如下四个特点: –永远不要主动调用某个对象的finalize方法,该方法应交给垃圾回收机制调用。 –finalize方法的何时被调用,是否被调用具有不确定性。不要把finalize方法当成一定会被执行的方法。 –当JVM执行去活对象的finalize方法时,可能使该对象,或系统中其他对象重新变成激活状态。 –当JVM执行finalize方法时出现了异常,垃圾回收机制不会报告异常,程序继续执行。
对象的软、弱和虚引用
•强引用(StrongReference)
•软引用-软引用需要通过SoftReference类来实现,当一个对象只具有软引用时,它有可能被垃圾回收机制回 收。
•弱引用-弱引用通过WeakReference类实现,弱引用和软引用很像,但弱引用的引用级别更低。对于只有弱引 用的对象而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。
•虚引用-虚引用通过PhantomReference类实现,虚应用完全类似于没有引用。虚引用对对象本身没有太大影 响,对象甚至感觉不到虚引用的存在。
修饰符的适用范围
使用JAR文件的好处
•1.安全 •2.加快下载速度 •3.压缩 •4.包封装 •5.可移植性 jar命令详解
•-c 创建新文档,-t 列出存档内容的列表, -x 展开存档中的命名文件 •-u 更新已存在的存档,-v生成详细输出到标准输出上 •-f 指定存档文件名,-m 包含 来自标文件的标明信息 •-o 只存储方式:未用ZIP压缩格式 •-m 不产生所有项的清单文件,- I 为指定的jar文件产生索引信息 •-c 改变到指定的目录, 创建可执行的JAR包
•1.使用平台相关的编译器将整个应用编译成平台相关的可执行性文件 •2.为整个应用编辑一个批处理文件 关于JAR包的技巧
•相当于一个压缩文件。 •可使用WinRAR来压缩JAR包。 •也可使用WinRAR来查看JAR包。
现在贴出代码:
public class AutoBoxingUnboxing { public static void main(String[] args) { // 直接把一个基本类型变量赋给Integer对象 Integer inObj = 5; // 直接把一个boolean类型变量赋给一个Object类型的变量 Object boolObj = true; // 直接把一个Integer对象赋给int类型的变量 int it = inObj; if (boolObj instanceof Boolean) { // 先把Object对象强制类型转换为Boolean类型,再赋给boolean变量 boolean b = (Boolean) boolObj; System.out.println(b); } // true } }
public class Primitive2String { public static void main(String[] args) { String intStr = "123"; // 把一个特定字符串转换成int变量 int it1 = Integer.parseInt(intStr); int it2 = new Integer(intStr); System.out.println(it2); String floatStr = "4.56"; // 把一个特定字符串转换成float变量 float ft1 = Float.parseFloat(floatStr); float ft2 = new Float(floatStr); System.out.println(ft2); // 把一个float变量转换成String变量 String ftStr = String.valueOf(2.345f); System.out.println(ftStr); // 把一个double变量转换成String变量 String dbStr = String.valueOf(3.344); System.out.println(dbStr); // 把一个boolean变量转换成String变量 String boolStr = String.valueOf(true); System.out.println(boolStr.toUpperCase()); } // 123 // 4.56 // 2.345 // 3.344 // TRUE }
public class UnsignedTest { public static void main(String[] args) { byte b = -3; // 将byte类型的-3转换为无符号整数。 System.out.println("byte类型的-3对应的无符号整数:" + Byte.toUnsignedInt(b)); // 输出253 // 指定使用16进制解析无符号整数 int val = Integer.parseUnsignedInt("ab", 16); System.out.println(val); // 输出171 // 将-12转换为无符号int型,然后转换为16进制的字符串 System.out.println(Integer.toUnsignedString(-12, 16)); // 输出fffffff4 // 将两个数转换为无符号整数后相除 System.out.println(Integer.divideUnsigned(-2, 3)); // 将两个数转换为无符号整数相除后求余 System.out.println(Integer.remainderUnsigned(-2, 7)); } }
public class WrapperClassCompare { public static void main(String[] args) { Integer a = new Integer(6); // 输出true System.out.println("6的包装类实例是否大于5.0" + (a > 5.0)); System.out.println("比较2个包装类的实例是否相等:" + (new Integer(2) == new Integer(2))); // 输出false // 通过自动装箱,允许把基本类型值赋值给包装类的实例 Integer ina = 2; Integer inb = 2; System.out.println("两个2自动装箱后是否相等:" + (ina == inb)); // 输出true Integer biga = 128; Integer bigb = 128; System.out.println("两个128自动装箱后是否相等:" + (biga == bigb)); // 输出false } // 6的包装类实例是否大于5.0true // 比较2个包装类的实例是否相等:false // 两个2自动装箱后是否相等:true // 两个128自动装箱后是否相等:false }
public class EqualTest { public static void main(String[] args) { int it = 65; float fl = 65.0f; // 将输出true System.out.println("65和65.0f是否相等?" + (it == fl)); char ch = 'A'; // 将输出true System.out.println("65和'A'是否相等?" + (it == ch)); String str1 = new String("hello"); String str2 = new String("hello"); // 将输出false System.out.println("str1和str2是否相等?" + (str1 == str2)); // 将输出true System.out.println("str1是否equals str2?" + (str1.equals(str2))); // 由于java.lang.String与EqualTest类没有继承关系, // 所以下面语句导致编译错误 // System.out.println("hello" == new EqualTest()); } // 65和65.0f是否相等?true // 65和'A'是否相等?true // str1和str2是否相等?false // str1是否equals str2?true }
// 定义一个Person类 class Person { // 重写equals()方法,提供自定义的相等标准 public boolean equals(Object obj) { // 不加判断,总是返回true,即Person对象与任何对象都相等 return true; } } // 定义一个Dog空类 class Dog { } public class OverrideEqualsError { public static void main(String[] args) { Person p = new Person(); System.out.println("Person对象是否equals Dog对象?" + p.equals(new Dog())); System.out.println("Person对象是否equals String对象?" + p.equals(new String("Hello"))); } // Person对象是否equals Dog对象?true // Person对象是否equals String对象?true }
class Person { private String name; private String idStr; public Person() { } public Person(String name, String idStr) { this.name = name; this.idStr = idStr; } // 此处省略name和idStr的setter和getter方法。 // name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } // idStr的setter和getter方法 public void setIdStr(String idStr) { this.idStr = idStr; } public String getIdStr() { return this.idStr; } // 重写equals()方法,提供自定义的相等标准 public boolean equals(Object obj) { // 如果两个对象为同一个对象 if (this == obj) return true; // 只有当obj是Person对象 if (obj != null && obj.getClass() == Person.class) { Person personObj = (Person) obj; // 并且当前对象的idStr与obj对象的idStr相等才可判断两个对象相等 if (this.getIdStr().equals(personObj.getIdStr())) { return true; } } return false; } } public class OverrideEqualsRight { public static void main(String[] args) { Person p1 = new Person("孙悟空", "12343433433"); Person p2 = new Person("孙行者", "12343433433"); Person p3 = new Person("孙悟饭", "99933433"); // p1和p2的idStr相等,所以输出true System.out.println("p1和p2是否相等?" + p1.equals(p2)); // p2和p3的idStr不相等,所以输出false System.out.println("p2和p3是否相等?" + p2.equals(p3)); } }
class Person { private String name; public Person(String name) { this.name = name; } } public class PrintObject { public static void main(String[] args) { // 创建一个Person对象,将之赋给p变量 Person p = new Person("孙悟空"); // 打印p所引用的Person对象 System.out.println(p); } }
public class StringCompareTest { public static void main(String[] args) { // s1直接引用常量池中的"疯狂Java" String s1 = "疯狂Java"; String s2 = "疯狂"; String s3 = "Java"; // s4后面的字符串值可以在编译时就确定下来 // s4直接引用常量池中的"疯狂Java" String s4 = "疯狂" + "Java"; // s5后面的字符串值可以在编译时就确定下来 // s5直接引用常量池中的"疯狂Java" String s5 = "疯" + "狂" + "Java"; // s6后面的字符串值不能在编译时就确定下来, // 不能引用常量池中的字符串 String s6 = s2 + s3; // 使用new调用构造器将会创建一个新的String对象, // s7引用堆内存中新创建的String对象 String s7 = new String("疯狂Java"); System.out.println(s1 == s4); // 输出true System.out.println(s1 == s5); // 输出true System.out.println(s1 == s6); // 输出false System.out.println(s1 == s7); // 输出false } }
class Apple { private String color; private double weight; public Apple() { } // 提供有参数的构造器 public Apple(String color, double weight) { this.color = color; this.weight = weight; } // color的setter和getter方法 public void setColor(String color) { this.color = color; } public String getColor() { return this.color; } // weight的setter和getter方法 public void setWeight(double weight) { this.weight = weight; } public double getWeight() { return this.weight; } // 重写toString方法,用于实现Apple对象的"自我描述" public String toString() { return "一个苹果,颜色是:" + color + ",重量是:" + weight; } // public String toString() // { // return "Apple[color=" + color + ",weight=" + weight + "]"; // } } public class ToStringTest { public static void main(String[] args) { Apple a = new Apple("红色", 5.68); // 打印Apple对象 System.out.println(a); } }
public class NullAccessStatic { private static void test() { System.out.println("static修饰的类方法"); } public static void main(String[] args) { // 定义一个NullAccessStatic变量,其值为null NullAccessStatic nas = null; // 使用null对象调用所属类的静态方法 nas.test(); // static修饰的类方法 } }
class Singleton { // 使用一个类变量来缓存曾经创建的实例 private static Singleton instance; // 将构造器使用private修饰,隐藏该构造器 private Singleton() { } // 提供一个静态方法,用于返回Singleton实例 // 该方法可以加入自定义的控制,保证只产生一个Singleton对象 public static Singleton getInstance() { // 如果instance为null,表明还不曾创建Singleton对象 // 如果instance不为null,则表明已经创建了Singleton对象, // 将不会重新创建新的实例 if (instance == null) { // 创建一个Singleton对象,并将其缓存起来 instance = new Singleton(); } return instance; } } public class SingletonTest { public static void main(String[] args) { // 创建Singleton对象不能通过构造器, // 只能通过getInstance方法来得到实例 Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); // 将输出true } // true }
public class Address { private final String detail; private final String postCode; // 在构造器里初始化两个实例变量 public Address() { this.detail = ""; this.postCode = ""; } public Address(String detail, String postCode) { this.detail = detail; this.postCode = postCode; } // 仅为两个实例变量提供getter方法 public String getDetail() { return this.detail; } public String getPostCode() { return this.postCode; } // 重写equals()方法,判断两个对象是否相等。 public boolean equals(Object obj) { if (this == obj) { return true; } if (obj != null && obj.getClass() == Address.class) { Address ad = (Address) obj; // 当detail和postCode相等时,可认为两个Address对象相等。 if (this.getDetail().equals(ad.getDetail()) && this.getPostCode().equals(ad.getPostCode())) { return true; } } return false; } public int hashCode() { return detail.hashCode() + postCode.hashCode() * 31; } }
class CacheImmutale { private static int MAX_SIZE = 10; // 使用数组来缓存已有的实例 private static CacheImmutale[] cache = new CacheImmutale[MAX_SIZE]; // 记录缓存实例在缓存中的位置,cache[pos-1]是最新缓存的实例 private static int pos = 0; private final String name; private CacheImmutale(String name) { this.name = name; } public String getName() { return name; } public static CacheImmutale valueOf(String name) { // 遍历已缓存的对象, for (int i = 0; i < MAX_SIZE; i++) { // 如果已有相同实例,直接返回该缓存的实例 if (cache[i] != null && cache[i].getName().equals(name)) { return cache[i]; } } // 如果缓存池已满 if (pos == MAX_SIZE) { // 把缓存的第一个对象覆盖,即把刚刚生成的对象放在缓存池的最开始位置。 cache[0] = new CacheImmutale(name); // 把pos设为1 pos = 1; } else { // 把新创建的对象缓存起来,pos加1 cache[pos++] = new CacheImmutale(name); } return cache[pos - 1]; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj != null && obj.getClass() == CacheImmutale.class) { CacheImmutale ci = (CacheImmutale) obj; return name.equals(ci.getName()); } return false; } public int hashCode() { return name.hashCode(); } } public class CacheImmutaleTest { public static void main(String[] args) { CacheImmutale c1 = CacheImmutale.valueOf("hello"); CacheImmutale c2 = CacheImmutale.valueOf("hello"); // 下面代码将输出true System.out.println(c1 == c2); } }
public class FinalErrorTest { // 定义一个final修饰的实例变量 // 系统不会对final成员变量进行默认初始化 final int age; { // age没有初始化,所以此处代码将引起错误。 System.out.println(age); age = 6; System.out.println(age); } public static void main(String[] args) { new FinalErrorTest(); } }
public class FinalLocalTest { public static void main(String[] args) { // 定义一个普通局部变量 final int a = 5; System.out.println(a); } }
public class FinalLocalVariableTest { public void test(final int a) { // 不能对final修饰的形参赋值,下面语句非法 // a = 5; } public static void main(String[] args) { // 定义final局部变量时指定默认值,则str变量无法重新赋值 final String str = "hello"; // 下面赋值语句非法 // str = "Java"; // 定义final局部变量时没有指定默认值,则d变量可被赋值一次 final double d; // 第一次赋初始值,成功 d = 5.6; // 对final变量重复赋值,下面语句非法 // d = 3.4; } }
public class FinalMethodTest { public final void test() { } } class Sub extends FinalMethodTest { // 下面方法定义将出现编译错误,不能重写final方法 public void test() { } }
class Person { private int age; public Person() { } // 有参数的构造器 public Person(int age) { this.age = age; } // 省略age的setter和getter方法 // age的setter和getter方法 public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } } public class FinalReferenceTest { public static void main(String[] args) { // final修饰数组变量,iArr是一个引用变量 final int[] iArr = { 5, 6, 12, 9 }; System.out.println(Arrays.toString(iArr)); // 对数组元素进行排序,合法 Arrays.sort(iArr); System.out.println(Arrays.toString(iArr)); // 对数组元素赋值,合法 iArr[2] = -8; System.out.println(Arrays.toString(iArr)); // 下面语句对iArr重新赋值,非法 // iArr = null; // final修饰Person变量,p是一个引用变量 final Person p = new Person(45); // 改变Person对象的age实例变量,合法 p.setAge(23); System.out.println(p.getAge()); // 下面语句对p重新赋值,非法 // p = null; } }
public class FinalReplaceTest { public static void main(String[] args) { // 下面定义了4个final“宏变量” final int a = 5 + 2; final double b = 1.2 / 3; final String str = "疯狂" + "Java"; final String book = "疯狂Java讲义:" + 99.0; // 下面的book2变量的值因为调用了方法,所以无法在编译时被确定下来 final String book2 = "疯狂Java讲义:" + String.valueOf(99.0); // ① System.out.println(book == "疯狂Java讲义:99.0"); System.out.println(book2 == "疯狂Java讲义:99.0"); } }
public class FinalVariableTest { // 定义成员变量时指定默认值,合法。 final int a = 6; // 下面变量将在构造器或初始化块中分配初始值 final String str; final int c; final static double d; // 既没有指定默认值,又没有在初始化块、构造器中指定初始值, // 下面定义的ch实例变量是不合法的。 // final char ch; // 初始化块,可对没有指定默认值的实例变量指定初始值 { // 在初始化块中为实例变量指定初始值,合法 str = "Hello"; // 定义a实例变量时已经指定了默认值, // 不能为a重新赋值,因此下面赋值语句非法 // a = 9; } // 静态初始化块,可对没有指定默认值的类变量指定初始值 static { // 在静态初始化块中为类变量指定初始值,合法 d = 5.6; } // 构造器,可对既没有指定默认值、有没有在初始化块中 // 指定初始值的实例变量指定初始值 public FinalVariableTest() { // 如果在初始化块中已经对str指定了初始化值, // 构造器中不能对final变量重新赋值,下面赋值语句非法 // str = "java"; c = 5; } public void changeFinal() { // 普通方法不能为final修饰的成员变量赋值 // d = 1.2; // 不能在普通方法中为final成员变量指定初始值 // ch = 'a'; } public static void main(String[] args) { FinalVariableTest ft = new FinalVariableTest(); System.out.println(ft.a); System.out.println(ft.c); System.out.println(ft.d); } }
public class ImmutableStringTest { public static void main(String[] args) { String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1 == str2); // 输出false System.out.println(str1.equals(str2)); // 输出true // 下面两次输出的hashCode相同 System.out.println(str1.hashCode()); System.out.println(str2.hashCode()); } }
public class IntegerCacheTest { public static void main(String[] args) { // 生成新的Integer对象 Integer in1 = new Integer(6); // 生成新的Integer对象,并缓存该对象 Integer in2 = Integer.valueOf(6); // 直接从缓存中取出Ineger对象 Integer in3 = Integer.valueOf(6); System.out.println(in1 == in2); // 输出false System.out.println(in2 == in3); // 输出true // 由于Integer只缓存-128~127之间的值, // 因此200对应的Integer对象没有被缓存。 Integer in4 = Integer.valueOf(200); Integer in5 = Integer.valueOf(200); System.out.println(in4 == in5); // 输出false } }
class Name { private String firstName; private String lastName; public Name() { } public Name(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // 省略firstName、lastName的setter和getter方法 public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return this.firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return this.lastName; } } public class Person { private final Name name; public Person(Name name) { this.name = name; } public Name getName() { return name; } public static void main(String[] args) { Name n = new Name("悟空", "孙"); Person p = new Person(n); // Person对象的name的firstName值为"悟空" System.out.println(p.getName().getFirstName()); // 改变Person对象name的firstName值 n.setFirstName("八戒"); // Person对象的name的firstName值被改为"八戒" System.out.println(p.getName().getFirstName()); } }
public class PrivateFinalMethodTest { private final void test() { } } class Sub extends PrivateFinalMethodTest { // 下面方法定义将不会出现问题 public void test() { } }
public class StringJoinTest { public static void main(String[] args) { String s1 = "疯狂Java"; // s2变量引用的字符串可以编译时就确定出来, // 因此s2直接引用常量池中已有的"疯狂Java"字符串 String s2 = "疯狂" + "Java"; System.out.println(s1 == s2); // 定义2个字符串直接量 String str1 = "疯狂"; // ① String str2 = "Java"; // ② // 将str1和str2进行连接运算 String s3 = str1 + str2; System.out.println(s1 == s3); } }
public class CarSpeedMeter extends SpeedMeter { public double getRadius() { return 0.28; } public static void main(String[] args) { CarSpeedMeter csm = new CarSpeedMeter(); csm.setTurnRate(15); System.out.println(csm.getSpeed()); } }
public class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } public void setRadius(double radius) { this.radius = radius; } // 重写Shape类的的计算周长的抽象方法 public double calPerimeter() { return 2 * Math.PI * radius; } // 重写Shape类的的返回形状的抽象方法 public String getType() { return getColor() + "圆形"; } public static void main(String[] args) { Shape s1 = new Triangle("黑色", 3, 4, 5); Shape s2 = new Circle("黄色", 3); System.out.println(s1.getType()); System.out.println(s1.calPerimeter()); System.out.println(s2.getType()); System.out.println(s2.calPerimeter()); } }
public abstract class Shape { { System.out.println("执行Shape的初始化块..."); } private String color; // 定义一个计算周长的抽象方法 public abstract double calPerimeter(); // 定义一个返回形状的抽象方法 public abstract String getType(); // 定义Shape的构造器,该构造器并不是用于创建Shape对象, // 而是用于被子类调用 public Shape() { } public Shape(String color) { System.out.println("执行Shape的构造器..."); this.color = color; } // 省略color的setter和getter方法 public void setColor(String color) { this.color = color; } public String getColor() { return this.color; } }
public abstract class SpeedMeter { // 转速 private double turnRate; public SpeedMeter() { } // 把返回车轮半径的方法定义成抽象方法 public abstract double getRadius(); public void setTurnRate(double turnRate) { this.turnRate = turnRate; } // 定义计算速度的通用算法 public double getSpeed() { // 速度等于 车轮半径 * 2 * PI * 转速 return java.lang.Math.PI * 2 * getRadius() * turnRate; } }
public class Triangle extends Shape { // 定义三角形的三边 private double a; private double b; private double c; public Triangle(String color, double a, double b, double c) { super(color); this.setSides(a, b, c); } public void setSides(double a, double b, double c) { if (a >= b + c || b >= a + c || c >= a + b) { System.out.println("三角形两边之和必须大于第三边"); return; } this.a = a; this.b = b; this.c = c; } // 重写Shape类的的计算周长的抽象方法 public double calPerimeter() { return a + b + c; } // 重写Shape类的的返回形状的抽象方法 public String getType() { return "三角形"; } }
public class AddCommand implements Command { public void process(int[] target) { int sum = 0; for (int tmp : target) { sum += tmp; } System.out.println("数组元素的总和是:" + sum); } } **************************************************** public class BetterPrinter implements Output { private String[] printData = new String[MAX_CACHE_LINE * 2]; // 用以记录当前需打印的作业数 private int dataNum = 0; public void out() { // 只要还有作业,继续打印 while (dataNum > 0) { System.out.println("高速打印机正在打印:" + printData[0]); // 把作业队列整体前移一位,并将剩下的作业数减1 System.arraycopy(printData, 1, printData, 0, --dataNum); } } public void getData(String msg) { if (dataNum >= MAX_CACHE_LINE * 2) { System.out.println("输出队列已满,添加失败"); } else { // 把打印数据添加到队列里,已保存数据的数量加1。 printData[dataNum++] = msg; } } } ************************************************ public interface Command { // 接口里定义的process()方法用于封装“处理行为” void process(int[] target); } ********************************************** public class CommandTest { public static void main(String[] args) { ProcessArray pa = new ProcessArray(); int[] target = { 3, -4, 6, 4 }; // 第一次处理数组,具体处理行为取决于PrintCommand pa.process(target, new PrintCommand()); System.out.println("------------------"); // 第二次处理数组,具体处理行为取决于AddCommand pa.process(target, new AddCommand()); } } ************************************************* public class Computer { private Output out; public Computer(Output out) { this.out = out; } // 定义一个模拟获取字符串输入的方法 public void keyIn(String msg) { out.getData(msg); } // 定义一个模拟打印的方法 public void print() { out.out(); } } ********************************************** interface interfaceA { int PROP_A = 5; void testA(); } interface interfaceB { int PROP_B = 6; void testB(); } interface interfaceC extends interfaceA, interfaceB { int PROP_C = 7; void testC(); } public class InterfaceExtendsTest { public static void main(String[] args) { System.out.println(interfaceC.PROP_A); System.out.println(interfaceC.PROP_B); System.out.println(interfaceC.PROP_C); } } ************************************************** public interface Output { // 接口里定义的成员变量只能是常量 int MAX_CACHE_LINE = 50; // 接口里定义的普通方法只能是public的抽象方法 void out(); void getData(String msg); // 在接口中定义默认方法,需要使用default修饰 default void print(String... msgs) { for (String msg : msgs) { System.out.println(msg); } } // 在接口中定义默认方法,需要使用default修饰 default void test() { System.out.println("默认的test()方法"); } // 在接口中定义类方法,需要使用static修饰 static String staticTest() { return "接口里的类方法"; } } ********************************************** public class OutputFactory { public Output getOutput() { // return new Printer(); return new BetterPrinter(); } public static void main(String[] args) { OutputFactory of = new OutputFactory(); Computer c = new Computer(of.getOutput()); c.keyIn("轻量级Java EE企业应用实战"); c.keyIn("疯狂Java讲义"); c.print(); } } *********************************************** public class OutputFieldTest { public static void main(String[] args) { // 访问另一个包中的Output接口的MAX_CACHE_LINE System.out.println(lee.Output.MAX_CACHE_LINE); // 下面语句将引起"为final变量赋值"的编译异常 // lee.Output.MAX_CACHE_LINE = 20; // 使用接口来调用类方法 System.out.println(lee.Output.staticTest()); } } ************************************************ public class PrintCommand implements Command { public void process(int[] target) { for (int tmp : target) { System.out.println("迭代输出目标数组的元素:" + tmp); } } } *********************************************** // 定义一个Product接口 interface Product { int getProduceTime(); } // 让Printer类实现Output和Product接口 public class Printer implements Output, Product { private String[] printData = new String[MAX_CACHE_LINE]; // 用以记录当前需打印的作业数 private int dataNum = 0; public void out() { // 只要还有作业,继续打印 while (dataNum > 0) { System.out.println("打印机打印:" + printData[0]); // 把作业队列整体前移一位,并将剩下的作业数减1 System.arraycopy(printData, 1, printData, 0, --dataNum); } } public void getData(String msg) { if (dataNum >= MAX_CACHE_LINE) { System.out.println("输出队列已满,添加失败"); } else { // 把打印数据添加到队列里,已保存数据的数量加1。 printData[dataNum++] = msg; } } public int getProduceTime() { return 45; } public static void main(String[] args) { // 创建一个Printer对象,当成Output使用 Output o = new Printer(); o.getData("轻量级Java EE企业应用实战"); o.getData("疯狂Java讲义"); o.out(); o.getData("疯狂Android讲义"); o.getData("疯狂Ajax讲义"); o.out(); // 调用Output接口中定义的默认方法 o.print("孙悟空", "猪八戒", "白骨精"); o.test(); // 创建一个Printer对象,当成Product使用 Product p = new Printer(); System.out.println(p.getProduceTime()); // 所有接口类型的引用变量都可直接赋给Object类型的变量 Object obj = p; } } ************************************************* public class ProcessArray { public void process(int[] target, Command cmd) { cmd.process(target); } }
public class AccessStaticInnerClass { static class StaticInnerClass { private static int prop1 = 5; private int prop2 = 9; } public void accessInnerProp() { // System.out.println(prop1); // 上面代码出现错误,应改为如下形式: // 通过类名访问静态内部类的类成员 System.out.println(StaticInnerClass.prop1); // System.out.println(prop2); // 上面代码出现错误,应改为如下形式: // 通过实例访问静态内部类的实例成员 System.out.println(new StaticInnerClass().prop2); } } ************************************************** abstract class Device { private String name; public abstract double getPrice(); public Device() { } public Device(String name) { this.name = name; } // 此处省略了name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } } public class AnonymousInner { public void test(Device d) { System.out.println("购买了一个" + d.getName() + ",花掉了" + d.getPrice()); } public static void main(String[] args) { AnonymousInner ai = new AnonymousInner(); // 调用有参数的构造器创建Device匿名实现类的对象 ai.test(new Device("电子示波器") { public double getPrice() { return 67.8; } }); // 调用无参数的构造器创建Device匿名实现类的对象 Device d = new Device() { // 初始化块 { System.out.println("匿名内部类的初始化块..."); } // 实现抽象方法 public double getPrice() { return 56.2; } // 重写父类的实例方法 public String getName() { return "键盘"; } }; ai.test(d); } } ********************************************* interface Product { public double getPrice(); public String getName(); } public class AnonymousTest { public void test(Product p) { System.out.println("购买了一个" + p.getName() + ",花掉了" + p.getPrice()); } public static void main(String[] args) { AnonymousTest ta = new AnonymousTest(); // 调用test()方法时,需要传入一个Product参数, // 此处传入其匿名实现类的实例 ta.test(new Product() { public double getPrice() { return 567.8; } public String getName() { return "AGP显卡"; } }); } } ******************************************* interface A { void test(); } public class ATest { public static void main(String[] args) { int age = 8; // ① // 下面代码将会导致编译错误 // 由于age局部变量被匿名内部类访问了,因此age相当于被final修饰了 age = 2; A a = new A() { public void test() { // 在Java 8以前下面语句将提示错误:age必须使用final修饰 // 从Java 8开始,匿名内部类、局部内部类允许访问非final的局部变量 System.out.println(age); } }; a.test(); } } ************************************************* public class Cow { private double weight; // 外部类的两个重载的构造器 public Cow() { } public Cow(double weight) { this.weight = weight; } // 定义一个非静态内部类 private class CowLeg { // 非静态内部类的两个实例变量 private double length; private String color; // 非静态内部类的两个重载的构造器 public CowLeg() { } public CowLeg(double length, String color) { this.length = length; this.color = color; } // 下面省略length、color的setter和getter方法 public void setLength(double length) { this.length = length; } public double getLength() { return this.length; } public void setColor(String color) { this.color = color; } public String getColor() { return this.color; } // 非静态内部类的实例方法 public void info() { System.out.println("当前牛腿颜色是:" + color + ", 高:" + length); // 直接访问外部类的private修饰的成员变量 System.out.println("本牛腿所在奶牛重:" + weight); // ① } } public void test() { CowLeg cl = new CowLeg(1.12, "黑白相间"); cl.info(); } public static void main(String[] args) { Cow cow = new Cow(378.9); cow.test(); } } ********************************************** class Out { // 定义一个内部类,不使用访问控制符, // 即只有同一个包中其他类可访问该内部类 class In { public In(String msg) { System.out.println(msg); } } } public class CreateInnerInstance { public static void main(String[] args) { Out.In in = new Out().new In("测试信息"); /* * 上面代码可改为如下三行代码: 使用OutterClass.InnerClass的形式定义内部类变量 Out.In in; * 创建外部类实例,非静态内部类实例将寄存在该实例中 Out out = new Out(); * 通过外部类实例和new来调用内部类构造器创建非静态内部类实例 in = out.new In("测试信息"); */ } } ************************************************ class StaticOut { // 定义一个静态内部类,不使用访问控制符, // 即同一个包中其他类可访问该内部类 static class StaticIn { public StaticIn() { System.out.println("静态内部类的构造器"); } } } public class CreateStaticInnerInstance { public static void main(String[] args) { StaticOut.StaticIn in = new StaticOut.StaticIn(); /* * 上面代码可改为如下两行代码: 使用OutterClass.InnerClass的形式定义内部类变量 StaticOut.StaticIn * in; 通过new来调用内部类构造器创建静态内部类实例 in = new StaticOut.StaticIn(); */ } } ************************************************** public class DiscernVariable { private String prop = "外部类的实例变量"; private class InClass { private String prop = "内部类的实例变量"; public void info() { String prop = "局部变量"; // 通过 外部类类名.this.varName 访问外部类实例变量 System.out.println("外部类的实例变量值:" + DiscernVariable.this.prop); // 通过 this.varName 访问内部类实例的变量 System.out.println("内部类的实例变量值:" + this.prop); // 直接访问局部变量 System.out.println("局部变量的值:" + prop); } } public void test() { InClass in = new InClass(); in.info(); } public static void main(String[] args) { new DiscernVariable().test(); } } ************************************************** public class InnerNoStatic { private class InnerClass { /* * 下面三个静态声明都将引发如下编译错误: 非静态内部类不能有静态声明 */ static { System.out.println("=========="); } private static int inProp; private static void test() { } } } ******************************************** public class LocalInnerClass { public static void main(String[] args) { // 定义局部内部类 class InnerBase { int a; } // 定义局部内部类的子类 class InnerSub extends InnerBase { int b; } // 创建局部内部类的对象 InnerSub is = new InnerSub(); is.a = 5; is.b = 8; System.out.println("InnerSub对象的a和b实例变量是:" + is.a + "," + is.b); } } ************************************************** public class Outer { private int outProp = 9; class Inner { private int inProp = 5; public void acessOuterProp() { // 非静态内部类可以直接访问外部类的private成员变量 System.out.println("外部类的outProp值:" + outProp); } } public void accessInnerProp() { // 外部类不能直接访问非静态内部类的实例变量, // 下面代码出现编译错误 // System.out.println("内部类的inProp值:" + inProp); // 如需访问内部类的实例变量,必须显式创建内部类对象 System.out.println("内部类的inProp值:" + new Inner().inProp); } public static void main(String[] args) { // 执行下面代码,只创建了外部类对象,还未创建内部类对象 Outer out = new Outer(); // ① out.accessInnerProp(); } } *********************************************** interface Teachable { void work(); } public class Programmer { private String name; // Programmer类的两个构造器 public Programmer() { } public Programmer(String name) { this.name = name; } // 此处省略了name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void work() { System.out.println(name + "在灯下认真敲键盘..."); } } ************************************************ public class StaticInnerClassTest { private int prop1 = 5; private static int prop2 = 9; static class StaticInnerClass { // 静态内部类里可以包含静态成员 private static int age; public void accessOuterProp() { // 下面代码出现错误: // 静态内部类无法访问外部类的实例变量 System.out.println(prop1); // 下面代码正常 System.out.println(prop2); } } } *********************************************** public class StaticTest { // 定义一个非静态的内部类,是一个空类 private class In { } // 外部类的静态方法 public static void main(String[] args) { // 下面代码引发编译异常,因为静态成员(main()方法) // 无法访问非静态成员(In类) new In(); } } ********************************************* public class SubClass extends Out.In { // 显示定义SubClass的构造器 public SubClass(Out out) { // 通过传入的Out对象显式调用In的构造器 out.super("hello"); } } ************************************************** public class TeachableProgrammer extends Programmer { public TeachableProgrammer() { } public TeachableProgrammer(String name) { super(name); } // 教学工作依然由TeachableProgrammer类定义 private void teach() { System.out.println(getName() + "教师在讲台上讲解..."); } private class Closure implements Teachable { /* * 非静态内部类回调外部类实现work方法,非静态内部类引用的作用仅仅是 向客户类提供一个回调外部类的途径 */ public void work() { teach(); } } // 返回一个非静态内部类引用,允许外部类通过该非静态内部类引用来回调外部类的方法 public Teachable getCallbackReference() { return new Closure(); } } ************************************************** public class TeachableProgrammerTest { public static void main(String[] args) { TeachableProgrammer tp = new TeachableProgrammer("李刚"); // 直接调用TeachableProgrammer类从Programmer类继承到的work方法 tp.work(); // 表面上调用的是Closure的work方法, // 实际上是回调TeachableProgrammer的teach方法 tp.getCallbackReference().work(); } }
public interface Command { // 接口里定义的process()方法用于封装“处理行为” void process(int[] target); } ********************************************** public class CommandTest { public static void main(String[] args) { ProcessArray pa = new ProcessArray(); int[] array = { 3, -4, 6, 4 }; // 处理数组,具体处理行为取决于匿名内部类 pa.process(array, new Command() { public void process(int[] target) { int sum = 0; for (int tmp : target) { sum += tmp; } System.out.println("数组元素的总和是:" + sum); } }); } } ********************************************** public class CommandTest2 { public static void main(String[] args) { ProcessArray pa = new ProcessArray(); int[] array = {3, -4, 6, 4}; // 处理数组,具体处理行为取决于匿名内部类 pa.process(array , (int[] target)->{ int sum = 0; for (int tmp : target ) { sum += tmp; } System.out.println("数组元素的总和是:" + sum); }); } } ************************************************* public class LambdaArrays { public static void main(String[] args) { String[] arr1 = new String[]{"java" , "fkava" , "fkit", "ios" , "android"}; Arrays.parallelSort(arr1, (o1, o2) -> o1.length() - o2.length()); System.out.println(Arrays.toString(arr1)); int[] arr2 = new int[]{3, -4 , 25, 16, 30, 18}; // left代表数组中前一个所索引处的元素,计算第一个元素时,left为1 // right代表数组中当前索引处的元素 Arrays.parallelPrefix(arr2, (left, right)-> left * right); System.out.println(Arrays.toString(arr2)); long[] arr3 = new long[5]; // operand代表正在计算的元素索引 Arrays.parallelSetAll(arr3 , operand -> operand * 5); System.out.println(Arrays.toString(arr3)); } } *********************************************** interface Eatable { void taste(); } interface Flyable { void fly(String weather); } interface Addable { int add(int a, int b); } public class LambdaQs { // 调用该方法需要Eatable对象 public void eat(Eatable e) { System.out.println(e); e.taste(); } // 调用该方法需要Flyable对象 public void drive(Flyable f) { System.out.println("我正在驾驶:" + f); f.fly("【碧空如洗的晴日】"); } // 调用该方法需要Addable对象 public void test(Addable add) { System.out.println("5与3的和为:" + add.add(5, 3)); } public static void main(String[] args) { LambdaQs lq = new LambdaQs(); // Lambda表达式的代码块只有一条语句,可以省略花括号。 lq.eat(()-> System.out.println("苹果的味道不错!")); // Lambda表达式的形参列表只有一个形参,省略圆括号 lq.drive(weather -> { System.out.println("今天天气是:" + weather); System.out.println("直升机飞行平稳"); }); // Lambda表达式的代码块只有一条语句,省略花括号 // 代码块中只有一条语句,即使该表达式需要返回值,也可以省略return关键字。 lq.test((a , b)->a + b); } } ************************************************* @FunctionalInterface interface FkTest { void run(); } public class LambdaTest { public static void main(String[] args) { // Runnable接口中只包含一个无参数的方法 // Lambda表达式代表的匿名方法实现了Runnable接口中唯一的、无参数的方法 // 因此下面的Lambda表达式创建了一个Runnable对象 Runnable r = () -> { for(int i = 0 ; i < 100 ; i ++) { System.out.println(); } }; // // 下面代码报错: 不兼容的类型: Object不是函数接口 // Object obj = () -> { // for(int i = 0 ; i < 100 ; i ++) // { // System.out.println(); // } // }; Object obj1 = (Runnable)() -> { for(int i = 0 ; i < 100 ; i ++) { System.out.println(); } }; // 同样的Lambda表达式可以被当成不同的目标类型,唯一的要求是: // Lambda表达式的形参列表与函数式接口中唯一的抽象方法的形参列表相同 Object obj2 = (FkTest)() -> { for(int i = 0 ; i < 100 ; i ++) { System.out.println(); } }; } } *********************************************** @FunctionalInterface interface Converter { Integer convert(String from); } @FunctionalInterface interface MyTest { String test(String a, int b, int c); } @FunctionalInterface interface YourTest { JFrame win(String title); } public class MethodRefer { public static void main(String[] args) { // 下面代码使用Lambda表达式创建Converter对象 // Converter converter1 = from -> Integer.valueOf(from); // // 方法引用代替Lambda表达式:引用类方法。 // // 函数式接口中被实现方法的全部参数传给该类方法作为参数。 // Converter converter1 = Integer::valueOf; // Integer val = converter1.convert("99"); // System.out.println(val); // 输出整数99 // 下面代码使用Lambda表达式创建Converter对象 // Converter converter2 = from -> "fkit.org".indexOf(from); // // 方法引用代替Lambda表达式:引用特定对象的实例方法。 // // 函数式接口中被实现方法的全部参数传给该方法作为参数。 // Converter converter2 = "fkit.org"::indexOf; // Integer value = converter2.convert("it"); // System.out.println(value); // 输出2 // 下面代码使用Lambda表达式创建MyTest对象 // MyTest mt = (a , b , c) -> a.substring(b , c); // 方法引用代替Lambda表达式:引用某类对象的实例方法。 // 函数式接口中被实现方法的第一个参数作为调用者, // 后面的参数全部传给该方法作为参数。 // MyTest mt = String::substring; // String str = mt.test("Java I Love you" , 2 , 9); // System.out.println(str); // 输出:va I Lo // 下面代码使用Lambda表达式创建YourTest对象 // YourTest yt = (String a) -> new JFrame(a); // 构造器引用代替Lambda表达式。 // 函数式接口中被实现方法的全部参数传给该构造器作为参数。 YourTest yt = JFrame::new; JFrame jf = yt.win("我的窗口"); System.out.println(jf); } } ************************************************ public class ProcessArray { public void process(int[] target, Command cmd) { cmd.process(target); } }
//interface public enum Gender implements GenderDesc { // 此处的枚举值必须调用对应构造器来创建 MALE("男") // 花括号部分实际上是一个类体部分 { public void info() { System.out.println("这个枚举值代表男性"); } }, FEMALE("女") { public void info() { System.out.println("这个枚举值代表女性"); } }; // 其他部分与codes\06\6.9\best\Gender.java中的Gender类完全相同 private final String name; // 枚举类的构造器只能使用private修饰 private Gender(String name) { this.name = name; } public String getName() { return this.name; } // 增加下面的info()方法,实现GenderDesc接口必须实现的方法 public void info() { System.out.println("这是一个用于用于定义性别的枚举类"); } } ********************************************** //interface public interface GenderDesc { void info(); } ********************************************** //better public enum Gender { MALE, FEMALE; private String name; public void setName(String name) { switch (this) { case MALE: if (name.equals("男")) { this.name = name; } else { System.out.println("参数错误"); return; } break; case FEMALE: if (name.equals("女")) { this.name = name; } else { System.out.println("参数错误"); return; } break; } } public String getName() { return this.name; } } ******************************************** public class GenderTest { public static void main(String[] args) { Gender g = Gender.valueOf("FEMALE"); g.setName("女"); System.out.println(g + "代表:" + g.getName()); // 此时设置name值时将会提示参数错误。 g.setName("男"); System.out.println(g + "代表:" + g.getName()); } } ****************************************** //best public enum Gender { // 此处的枚举值必须调用对应构造器来创建 MALE("男"), FEMALE("女"); private final String name; // 枚举类的构造器只能使用private修饰 private Gender(String name) { this.name = name; } public String getName() { return this.name; } } ******************************************** //abstract public enum Operation { PLUS { public double eval(double x, double y) { return x + y; } }, MINUS { public double eval(double x, double y) { return x - y; } }, TIMES { public double eval(double x, double y) { return x * y; } }, DIVIDE { public double eval(double x, double y) { return x / y; } }; // 为枚举类定义一个抽象方法 // 这个抽象方法由不同的枚举值提供不同的实现 public abstract double eval(double x, double y); public static void main(String[] args) { System.out.println(Operation.PLUS.eval(3, 4)); System.out.println(Operation.MINUS.eval(5, 4)); System.out.println(Operation.TIMES.eval(5, 4)); System.out.println(Operation.DIVIDE.eval(5, 4)); } } ******************************************** public class EnumTest { public void judge(SeasonEnum s) { // switch语句里的表达式可以是枚举值 switch (s) { case SPRING: System.out.println("春暖花开,正好踏青"); break; case SUMMER: System.out.println("夏日炎炎,适合游泳"); break; case FALL: System.out.println("秋高气爽,进补及时"); break; case WINTER: System.out.println("冬日雪飘,围炉赏雪"); break; } } public static void main(String[] args) { // 枚举类默认有一个values方法,返回该枚举类的所有实例 for (SeasonEnum s : SeasonEnum.values()) { System.out.println(s); } // 使用枚举实例时,可通过EnumClass.variable形式来访问 new EnumTest().judge(SeasonEnum.SPRING); } } ******************************************* public enum Gender { MALE, FEMALE; // 定义一个public修饰的实例变量 public String name; } ****************************** public class GenderTest { public static void main(String[] args) { // 通过Enum的valueOf()方法来获取指定枚举类的枚举值 Gender g = Enum.valueOf(Gender.class, "FEMALE"); // 直接为枚举值的name实例变量赋值 g.name = "女"; // 直接访问枚举值的name实例变量 System.out.println(g + "代表:" + g.name); } } ******************************************* public class Season { // 把Season类定义成不可变的,将其成员变量也定义成final的 private final String name; private final String desc; public static final Season SPRING = new Season("春天", "趁春踏青"); public static final Season SUMMER = new Season("夏天", "夏日炎炎"); public static final Season FALL = new Season("秋天", "秋高气爽"); public static final Season WINTER = new Season("冬天", "围炉赏雪"); public static Season getSeason(int seasonNum) { switch (seasonNum) { case 1: return SPRING; case 2: return SUMMER; case 3: return FALL; case 4: return WINTER; default: return null; } } // 将构造器定义成private访问权限 private Season(String name, String desc) { this.name = name; this.desc = desc; } // 只为name和desc提供getter方法 public String getName() { return this.name; } public String getDesc() { return this.desc; } } **************************************** public enum SeasonEnum { // 在第一行列出4个枚举实例 SPRING, SUMMER, FALL, WINTER; } ******************************************** public class SeasonTest { public SeasonTest(Season s) { System.out.println(s.getName() + ",这真是一个" + s.getDesc() + "的季节"); } public static void main(String[] args) { // 直接使用Season的FALL常量代表一个Season对象 new SeasonTest(Season.FALL); } }
public class FinalizeTest { private static FinalizeTest ft = null; public void info() { System.out.println("测试资源清理的finalize方法"); } public static void main(String[] args) throws Exception { // 创建FinalizeTest对象立即进入可恢复状态 new FinalizeTest(); // 通知系统进行资源回收 // System.gc(); //① // 强制垃圾回收机制调用可恢复对象的finalize()方法 // Runtime.getRuntime().runFinalization(); //② System.runFinalization(); // ③ ft.info(); } public void finalize() { // 让tf引用到试图回收的可恢复对象,即可恢复对象重新变成可达 ft = this; } } ************************************** public class GcTest { public static void main(String[] args) { for (int i = 0; i < 4; i++) { new GcTest(); // 下面两行代码的作用完全相同,强制系统进行垃圾回收 // System.gc(); Runtime.getRuntime().gc(); } } public void finalize() { System.out.println("系统正在清理GcTest对象的资源..."); } } ***************************************** public class PhantomReferenceTest { public static void main(String[] args) throws Exception { // 创建一个字符串对象 String str = new String("疯狂Java讲义"); // 创建一个引用队列 ReferenceQueue rq = new ReferenceQueue(); // 创建一个虚引用,让此虚引用引用到"疯狂Java讲义"字符串 PhantomReference pr = new PhantomReference(str, rq); // 切断str引用和"疯狂Java讲义"字符串之间的引用 str = null; // 取出虚引用所引用的对象,并不能通过虚引用获取被引用的对象,所以此处输出null System.out.println(pr.get()); // ① // 强制垃圾回收 System.gc(); System.runFinalization(); // 垃圾回收之后,虚引用将被放入引用队列中 // 取出引用队列中最先进入队列中的引用与pr进行比较 System.out.println(rq.poll() == pr); // ② } } ******************************************* public class ReferenceTest { public static void main(String[] args) throws Exception { // 创建一个字符串对象 String str = new String("疯狂Java讲义"); // 创建一个弱引用,让此弱引用引用到"疯狂Java讲义"字符串 WeakReference wr = new WeakReference(str); // ① // 切断str引用和"疯狂Java讲义"字符串之间的引用 str = null; // ② // 取出弱引用所引用的对象 System.out.println(wr.get()); // ③ // 强制垃圾回收 System.gc(); System.runFinalization(); // 再次取出弱引用所引用的对象 System.out.println(wr.get()); // ④ } } ******************************************** public class StatusTranfer { public static void test() { String a = new String("轻量级Java EE企业应用实战"); // ① a = new String("疯狂Java讲义"); // ② } public static void main(String[] args) { test(); // ③ } }
|



浙公网安备 33010602011771号