[疯狂Java讲义精粹] 第五章|面向对象(下)

本文深入探讨了Java中的面向对象特性,包括final关键字的作用,如何使用abstract定义抽象类和接口,enum创建枚举类,以及包装类的功能。文章还介绍了自动装箱、拆箱、基本类型与字符串之间的转换,并讲解了toString方法、equals与==的区别、final变量的初始化以及抽象方法和抽象类的规则。此外,还讨论了接口的用途、内部类和匿名内部类的使用,以及枚举类在switch语句中的应用。
摘要由CSDN通过智能技术生成

0. 几个关键字.

  1. final关键字修饰变量、方法和类: 系统不能为final变量重新赋值, 子类不允许覆盖父类的final方法, final类不能派生子类.
  2. abstract和interface两个关键字分别用于定义抽象类和接口. 抽象类和接口都是从多个子类中抽象出来的共同特征, 但抽象类主要作为多个类的模板, 接口则定义了多个类应遵守的规范.
  3. enum关键字用于创建枚举类. 枚举类是一种不能自由创建对象的类, 枚举类的对象在定义类时已经固定下来.

1. 包装类(Wrappe Class): Java为8种基本数据类型定义了相应的引用类型, 并称之为基本数据类型的包装类. 
基本数据类型byteshortintlongcharfloatdoubleboolean
包装类ByteShortIntegerLongCharacterFloatDoubleBoolean
  1. 八个包装类中除了Character外, 都可以通过传入一个字符串参数来构造包装类对象.(可能报错, java.lang.NumberFormatException.) 用字符串创建Boolean对象时, 如果传入的是"true"(不分大小写), 都会创建true对应的Boolean对象; 传入别的, 创建false对应的.
  2. 如果要获取包装类对象中包装的基本类型变量, 可以使用包装类提供的xxxValue()实例方法. 
    boolean bl = true;
    Boolean blObj = new Boolean(bl);     // 装箱
    boolean bb = bObj.booleanValue();    // 拆箱
  3. Java有自动装箱(AutoBoxing)和自动拆箱(AutoUnboxing)功能. 所谓AutoBoxing, 就是可以把基本类型的变量直接赋给对应的包装类变量(或者Object类(子类对象可以直接付给父类变量)). AutoUnboxing反之.
  4. 包装类可以实现基本类型变量和字符串之间的转换.
    - 字符串转基本类型: a. 利用包装类提供的parseXxx(String s)静态方法(Character外所有包装类都提供该方法). b. 利用包装类提供的XXX(String s)构造器.
    - 基本类型转字符串: a.利用String类提供的多个重载valueOf()方法. b. 将基本类型变量和""进行连接运算, 系统会自动把基本类型转换成字符串.
    String intStr = "123";
    int it1 = Integer.parseInt(intStr);
    int it2 = new Integer(intStr);
    String ftStr = String.valueOf(2.345f);
    String dbStr = String.valueOf(2.345);    // String dbStr = 2.345 + "";
  5. Java7 为所有包装类提供了静态的compare(xxx val1, xxx val2)方法. (相等返回零, val1<val2返回负值, cal1>val2返回正值.)

2. 常用方法:
  1. toString方法:
    - toString 方法是Object类的实例方法, 所有Java类都是Object的子类, 因此所有的Java对象都有toString()方法, 因此所有"对象"都可以和字符串进行连接运算(连接时, 系统自动调用Java对象的toString方法的返回值和字符串进行连接运算.)
    - System.out.println方法输出"对象"时, 输出的是对象的toString()方法的返回值. 所以toString通常用于输出"自我描述"信息(即该对象的状态信息).
    - 默认返回实现类的"类名@hashCOde"值, 要实现"自我描述"功能需重写toString方法. 通常如下格式
    public String toString()
    {
        //通常返回的格式是: 类名[Field1=值1, Field2=值2]
        return "Apple[color=" + color + ", weight=" + weight + "]";
    }
  2. ==运算符和equals方法:
    - ==运算符, 对于基本类型(不一定要求数据类型严格相同), 值相等时返回true; 对于引用类型, 指向同一个对象时, 返回true. String的equals()方法(Object提供的equals()方法比较地址, 与==同), 只要两个字符串所包含的字符序列相同就返回true(形如 str1.equals(str2)).

3. 常量池(constant pool) 用于管理在编译期被确定并被保存在已编译的.class文件中的一些数据. 包括关于类、方法、接口中的常量, 和字符串常量. JVM constant pool保证相同字符串直接量只有一个, 不会产生多个副本. (使用"hello"直接量时, JVM将会使用常量池来管理这些字符串; 使用new String("hello")时, JVM先是使用常量池管理"hello", 再调用String类构造器创建一个String对象, 新创建的String对象保存在堆内存中(即new String("hello")一共产生俩对象 羡慕.)
public boolean equals(Object obj)
{
    // 判断依据相关语句块
}

4. 单例(Singleton)类: 始终只能创建一个实例的类.
class Singleton
{
	private static Singleton instance;
	private Singleton(){}
	public static Singleton getInstance()
	{
		if(instance == null)
		{
			instance = new Singleton();
		}
		return instance;
	}
}
public class SingletonTest
{
	public static void main(String[] args)
	{
		Singleton s1 = Singleton.getInstance();
		Singleton s2 = Singleton.getInstance();
		System.out.println(s1 == s2);
	}
}

5. final 修饰类、变量和方法, 所修饰的类、变量和方法不可改变. 
  1. 不像普通成员变量, final成员变量(实例的和类的)必须有程序员显式初始化, 系统不会对final成员进行隐式初始化. 
  2. 系统不会对局部变量初始化, 必须由程序员显式初始化. 
  3. 若定义一个final变量时就赋值(被赋直接量, 或基本的算数表达式, 或字符串连接运算, 没有访问普通变量, 没有调用方法), 且该初始值可以在编译时就被确定下来, 那么这个final变量就不再是一个变量, 而是相当于一个直接量. (*编译器会把程序中所有用到该变量的地方直接替换成该变量的值.)
  4. final方法不能被重写, 可以重载.

6. abstract修饰符 用来定义抽象方法和抽象类, 有抽象方法的类只能被定义成抽象类, 抽象类可以没有抽象方法.
  1. 抽象方法不能有方法体, 抽象类不能实例化(抽象类的构造器不能用于创建实例, 主要用于被其子类调用.). 
  2. 有抽象方法的类(包括直接定义了抽象方法; 继承了一个抽象法类, 但没有完全实现父类包含的抽象方法, 以及实现了一个接口, 但没有完全实现接口包含的抽象方法3种情况) 只能被定义成抽象类.
  3. 定义方法: 普通方法上加abstract修饰符, 并把普通方法的方法体(花括号及其中内容)全部去掉, 并在方法后增加分号. 
    - public abstract void test();  是抽象方法.    - public void test(){}   是空方法体的普通方法.
  4. abstract只能修饰方法和类, abstract不能和final/static/private同时使用.
  5. 抽象类体现的是一种模板式的设计. 抽象类作为多个子类的通用模板, 子类在抽象类的基础上进行扩展、改造, 但子类总体上大致保留抽象类的行为方式.

7. 接口(interface): 抽象类是从多个类中抽象出模版, 如果再将其抽象彻底, 就得到更加特殊的"抽象类"--接口(接口里所有方法都是抽象方法.). 
  1. 接口定义的是多个类共同的公共行为规范, 这些行为是与外部进行交流的通道, 所以接口通常是定义一组公用方法. 接口体现的是设计规范和实现分离的设计哲学.
  2. interface定义:
    [修饰符] interface 接口名 extends 父接口1, 父接口2...
    {
        零到多个常量定义
        零到多个抽象方法定义
    }
    - 修饰符 可以使public 或 省略(省略为包访问权限).
    - 接口名 通常有多个有意义的单词连接而成, 每个单词首字母大写, 单词间无分隔符. 
  3. 由于接口定义的是一种规范, 因此接口里不能有构造器和初始化块定义, 可以有Field(只能是常量)、方法(只能是抽象实例方法)、内部类(包括内部接口、枚举)定义.
  4. 接口里定义的是多个类的公共行为规范, 因此接口里所有成员(常量、方法、内部类和枚举类)都是public访问权限. 
    - 接口里定义的Field是接口相关的, 而且只能是常量, 因此系统会自动为这些Field增加static和final两个修饰符.(就是说, 接口中定义Field时, 不管是否使用public static final修饰符, 接口里的Field都将使用这三个修饰符来修饰.) 
    - 同上, 接口里的方法总是使用public abstract修饰, 接口里定义的内部类、接口、枚举类都使用public static修饰. 
  5. 类似类, 一个java源文件中最多只能有一个public接口, 且文件名与该接口名相同. 
  6. 接口不能用于创建实例, 但接口可以用于声明引用类型变量.(用接口声明引用类型变量时, 引用类型变量必须引用到该接口的实现类的对象.)
  7. 一个类可以实现(implements)一个或多个接口.
    [修饰符] class 类名 extends 父类 implements 接口1, 接口2...
    {
        类体部分
    }

8. 面向接口编程
  1. 简单工厂模式. 
  2. 命令模式. 

9. 可以把一个类定义在另一个类内部, 这个内部的类, 叫内部类(or嵌套类), 包含内部类的类叫外部类(or宿主类). 
  1. * 外部类不能放访问内部类的实现细节. (内部类可以访问外部类的私有数据.) 
  2. 匿名内部类用于创建仅需要使用一次的类. 
  3. 成员内部类是一种与Field、方法、构造器和初始化块相似的类的成员(因为作为外部类的成员, 所以可以使用任意访问控制符, 如private、protected和public.); 局部内部类和匿名内部类则不是. 
  4. 如果有OuterClass和InnerClass两个类, 编译后生成OuterClass.class和OuterClass$InnerClass.class两个文件. 
  5. 如果外部类成员变量、内部类成员变量和内部类里方法的局部变量同名, 可以通过使用外部类.this、this作为限定来区分. (不用this的话默认 内部方法的变量->内部类Field->外部类Field.) 
  6. Java不允许在非静态内部类里定义静态成员. 
  7. static修饰的内部类叫 类内部类(or静态内部类). 
    - 外部类的上一级程序单元是包, 内部类的上一级程序单元是外部类, 因此外部类不可以使用static修饰, 内部类可以使用static将自身变成外部类相关, 而不是外部类实例相关. 
    - 可以在接口里定义内部类, 接口里定义的内部类默认用public static修饰(即接口内部类只能是静态内部类), 访问控制符只能是public(省略的话, 默认是public访问权限.). 
  8. * 使用内部类的方法: 
    - 1. 在外部类内部使用内部类. --> 直接Inner i = new Inner(); 就行. private修饰的内部类只能在外部类内部使用. 
    - 2. 在外部类以外使用非静态内部类. 
    在外部类以外的地方定义内部类(包括静态的和非静态的): 
    OuterClass.InnerClass varName; // 如果外部类有包名还要增加包名.
    在外部类以外的地方创建非静态内部类实例的语法(非静态内部类的构造器必须使用外部类对象来调用.):
    OuterInstance.new InnerConstructor();
    或者
    new Outer().newInner()  // 类名 与 构造器名肯定相等.
    创建非静态内部类的子类(依附于外部类的实例):
    public class SubClass extends Out.In
    {
        public SubClass(Out out)    // 传入个外部对象. 
        {
            out.super("hello");  // super代表In类的构造器. 
        }
    }
    - 3. 在外部类以外使用静态内部类. 
    创建方法:
    new OuterClass.InnerConstructor();
  9. 局部内部类由于只能在外部类的方法中使用, 所以不能用访问控制符和static修饰. 局部内部类的.class文件命名为: OuterClass$NInnerClass.class(比成员内部类的.class多了个数字'N', 因为同一个类里不能同时又两个同名成员内部类, 但可能多个同名局部内部类(位于不同方法中). ). 
  10. 匿名内部类: 适合创建只需要使用一次的类. 创建匿名内部类时会立即创建一个该类的实例, 这个类定义立即消失, 匿名内部类不能重复使用. 匿名内部类不能定义构造器, 因为匿名内部类没有类名. 
    new 父类构造器(实参列表)|实现接口()
    {
        匿名内部类的类体部分
    }
    从格式上看出来, 匿名内部类必须集成一个父类或实现一个接口(最多"一个"). 
    interface Product
    {
    	double getPrice();
    	String getName();
    }
    public class AnonymousTest
    {
    	public void test(Product p)
    	{
    		System.out.println("buy a " + p.getName()
    			+ ", spend " + p.getPrice());
    	}
    	public static void main(String[] args)
    	{
    		AnonymousTest at = new AnonymousTest();
    		at.test(new Product()    // <-- 匿名内部类. 
    		{
    			public double getPrice()
    			{
    				return 123.4;
    			}
    			public String getName()
    			{
    				return "shi";
    			}
    		});
    	}
    }
    * 匿名内部类访问外部类的局部变量, 必须使用final修饰符来修饰外部类的局部变量, 否则报错(WHY啊? ).  ----> 写一篇为啥这样.
  11. 闭包(closure) 和回调. page224

10. 枚举类: 实例有限而且固定的类. 
  1. enum关键字(与class和interface关键字地位相同)用来定义枚举类. 枚举类是种特殊的类, 可以有Field、方法, 可以实现一个或多个接口, 可以有构造器. 一个Java源文件中最多定义一个public访问权限的枚举类, 切文件名同该类名. 
    - enum定义的枚举类默认继承java.lang.Enum类(不是java.lang.Object类). java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口. 
    - 用enum定义的非抽象枚举类默认使用final修饰, 因此不能派生子类. 
    - 枚举类只能使用private访问控制符, 省略的话, 默认也是private. 
    - 枚举类的所有实例必须在第一行显示列出(否则不能产生实例), 系统自动给这些实例添加public static final修饰, 无需程序员显式添加. 
  2. switch(枚举类类名)
    {
        case 实例名1: ;    // 不需要用 (枚举类类名.实例名) 的形式
        case 实例名2: ;
    
    }
  3. java.lang.Enum类常用方法:
    0. 所有的枚举类都提供values方法, 可以方便地遍历所有枚举值. (for(Season s : Season.values()){})
    1. int compareTo(E o): 与指定枚举对象比较顺序. (该枚举对象位于制定枚举对象之后, 返回正整数; 之前, 返回负整数; 否则, 返回零.)
    2. String name(): 返回枚举实例的名称(即定义时列出的值之一). 通常优先考虑toString()方法, 因为它返回更友好的名称.
    3. String toString(): 返回枚举常量的名称. 与name方法类似, 但更常用.
    4. int ordinal(): 返回枚举值在枚举类中的索引值(从零开始).
    5. public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name): 静态方法, 返回指定枚举类型中指定名称的枚举值. 
    Gender g = Enum.valueOf(Gender.class, "FEMALE");    // Gender是枚举类类名, FEMALE是Gender的一个枚举值.
  4. 枚举类构造器:
    public enum Gender
    {
        MALE("男"), FEMALE("女");
        private final String name;
        private Gender(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return this.name;
        }
    }
  5. 用枚举类实现接口可以让每个枚举实例独立地实现所有方法. 
    public enum Gender implements GenderDesc
    {
    	MALE("男")
    	//花括号实际是类体部分, 相当于用了匿名内部类了
    	{
    		public void info()
    		{
    			System.out.println("代表男银.");
    		}
    	}, 
    	FEMALE("女")
    	{
    		public void info()
    		{
    			System.out.println("daibiaole ..");
    		}
    	};
    }
    编译生成Gender.class, Gender$1.class, Gender$2.class三个文件, 所以MALE和FEMALE是Gender的你名字类的实例, 而不是Gender的实例. 
  6. 枚举类里有抽象(abstract)方法 也不能使用abstract修饰该类. 

11. 垃圾回收机制
  1.  特征: 
    1. 垃圾回收机制支付额回收对内存中的对象, 不回收物理资源(如数据连接, 网络IO等). 
    2. 垃圾回收在合适的时候进行. 对象永久性是去饮用后, 系统会在合适的时候回收它所占的内存.
    3. 回收任何对象之前, 总会先调用它的finalize()方法, 该方法可能使该对象重新复活(让一个引用变量重新引用该对象), 从而导致垃圾回收机制取消回收. 
  2. 对象在内存中的状态: 
    1. 可达状态: 有一个以上引用变量引用它. 
    2. 可恢复状态: 程序中没有引用变量引用它, 则进入可恢复状态. 此时, 垃圾回收机制准备回收它, 回收之前, 调用它的finalize()方法进行资源清理(如果调用finalize()时重新让一个引用变量引用该对象, 则该对象变为可达状态; 否则变不可达状态). 
    3. 不可达状态: 只回收不可达状态的对象所占有的资源. 
  3. 强制垃圾回收: 程序无法精确控制Java垃圾回收的时机, 强制垃圾回收只是通知系统进行垃圾回收, 但系统是否进行回收依然不确定. 强制回收使用: 
    - 调用System类的gc()静态方法: System.gc()       gc: garbage collector.
    - 调用Runtime对象的gc()实例方法: Runtime.getRuntime().gc()
    --------------------------------------------------------------------------------------------
    System.runFinalization() 和 Runtime.getRuntime().runGinalization() 
    用以强制垃圾回收机制调用可恢复对象的finalize()方法.
    --------------------------------------------------------------------------------------------
  4. 运行时, 使用 (java -verbose:gc 类名) 的形式可以看到每次垃圾回收后的提示信息.
  5. finalize方法: 默认的清理资源的方法. 是Object类的实例方法, 原型为 (protected void finalize() throws Throwable): 当finalize()方法返回后对象消失, 垃圾回收机制开始执行. 原型中的 throws Throwable表示它可以抛出任何类型的异常. 
    - 不要主动调用某个对象的finalize()方法, 该方法应该交给垃圾回收机制调用. 
    - finalize() 方法何时被调用, 是否被调用具有不确定性, 不要把finalize()方法当成一定会被执行的方法. 
    - JVM执行可恢复对象的finalize()方法时, 可能使该对象或系统中其他对象重新变成可达状态. 
    - JVM执行finalize()方法时出现异常时, 垃圾回收机制不报告异常, 程序继续执行. 
  6. 对象的强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference). 

12. 
 
4个访问控制符互斥, 最多出现一个. abstract和final互斥, abstract和static互斥, abstract和private互斥. 对于初始化块和局部成员而言, 不能使用任何访问控制符, 所以看起来像使用了包访问控制符. 

13. JAR文件全称Java Archive File(Java档案文件). 
  1. JAR是种压缩文件, 与ZIP压缩文件兼容(区别是, 生成JAR时, 系统默认创建一个META-INF/MANIFEST.MF的清单文件.). 
  2. 好处: a.安全(JAR签名, 识别签名的用户可以使用.) b. 下载快(多个文件时每个都要创建一个HTTP连接.) c. 包封装(JAR包里的文件依赖于同一版本的类文件.)
  3. jar命令. (bin/jar.exe文件. 运行它需要lib/tools.jar文件, 但通常系统会自动加载tools.jar, 无需显示设置.) 
    - 创建JAR文件: jar cf test.jar test  (当前路径下的test路径下的全部内容生成test.jar文件放在当前目录. 如果已存在则覆盖.) 
    - 创建JAR, 并显示压缩过程:jar cvf test.jar test
    - 不使用清单文件: jar cvfM test.jar test 
    - 自定义清单文件内容: jar cvfm test.jar manifest.mf test    (其中manifest.mf 可以是任意后缀的文件, 都当成文本文档读取. 每行一个key-value对(必须放在每行最前), 格式 jey:<空格>value, 空格不能省. 文件开头不能有空行, 最后一行必须空行. )
    - 查看JAR包内容: jar tf test.jar   (如果包中内容特别多, 也可以用 (jar tf test.jar > a.txt) 将内容输出到当前目录下的a.txt中. 
    - 查看JAR包详细内容: jar tvf test.jar   
    - 解压缩: jar xf test.jar
    - 带提示信息的解压: jar xvf test.jar
    - 更新JAR文件: jar uf test.jar Hello.class    (如果test.jar中有Hello.class文件怎用新的替换它, 如果没有就添加进去.) 
    - 更新时显示详细信息: jar uvf test.jar Hello.class
    ---------------------------------------这十条就是输入jar回车后的提示嘛--------------------------------------
  4. Java程序的发布:
    1. 用平台相关的编译器将整个应用编译成平台相关的可执行文件. 
    2. 为应用编辑一个批处理文件. (Windows为例, 批处理文件中用命令 java package.MainClass(如果不想显示运行Java程的序命令行窗口, star javaw package.MainClass). 
    3. 做成可执行的JAR包.
    - windows下安装JRE时会将*.jar文件映射成由jaraw.exe打开, 所以双击JAR就能运行.
    - 创建可执行JAR包关键是: 让javaw命令知道JAR包中哪个是主类, javaw命令可以通过运行该主类运行程序. )
    - jar cvfe test.jar Test *.class  (把当前目录下的所有*.class文件压缩到test.jar保重, 并指定Test类作为程序的入口.  -e选项指定作为程序入口的主类的类名.) 
    - 运行上述JAR包: java命令(java -jar test.jar); javaw命令(javaw test.jar). 
  5. Java还能生成WAR(Web Archive File, 对应Web应用文档) 和 EAR(Enterprise Archive File,  企业应用文档), 它们的压缩格式及压缩方式与JAR一样, 只是后缀不同. 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值