疯狂JAVA讲义学习笔记5——面向对象2

包装类及其用法

Java包含8种基本数据类型,不支持面向对象的编程机制。
为了将8种基本数据类型的变量当成Object类型变量使用,Java提供了包装类(Wrapper Class)。

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

使用示例:

Float f1=new Float("4.56");
Booean blObj = new Boolean(b1);
  • 当包装类创建失败时,会引发
java.lang.NumberFormatException异常。
  • 获得包装类的基本类型变量
int i = integerObject.intValue();
  • 从JDK1.5之后,提供了自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)功能。即:
Integer intObj=5;
boolean b = (Boolean)boolObj;
  • 包装类的parseXxx(String)静态方法提供了字符串值转换为基本类型的值的方法;也可以使用包装类的构造器实现
  • String 类提供了多个重载valueOf()方法,用于将基本类型变量转换成字符串
  • 包装类的实例可与数值类型的值进行比较
  • 而两个包装类的实例进行比较的情况比较复杂,只有两个包装类引用指向同一个对象时才会返回true
  • 自动装箱的特例
Integer a=2;
Integer b=2;
a==b  //true

Integer a=128;
Integer b=128;
a==b  //false

其原因是-128~127之间的整数自动装箱成一个Integer实例时,会放入一个名为cache的数组中缓存起来。不在这个范围内的,系统总是重新创建一个Integer实例。

  • Java7 增强了包装类的功能,为所有包装类提供了一个静态的compare(xxx var1,xxx val2)方法,以方便进行值比较

处理对象

打印对象和toString方法

class Person{}
Person p=new Person();

//下面两句效果是一样的
System.out.println(p);
System.out.println(p.toString());
  • 所有Java对象都有toString实例方法
  • Java对象都可以与字符串进行连接运算
  • Object类提供的toString方法总是返回该对象实现类的“类名+@+hashCode”
  • toString()可以重写

== 和 equals

Java程序中测试两个变量是否相等有两种方式。

  • ==判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,即返回true
  • 对于两个引用类型的变量,必须指向同一个对象时,==才返回true
  • ==不可用于比较类型上没有父子关系的两个对象

“hello” 和 new String(“hello”)的区别

  • “hello”,JVM将会使用常量池来管理这些字符串
  • 当使用new String(“hello”)时,JVM会先使用常量池来管理”hello”直接量,再用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。new String(“hello”)一共产生两个对象。

常量池(constant pool)专门用于管理在编译期被确定并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口中的常量,还包括字符串常量。

JVM常量池保证相同的字符串(在编译期间可运算的值)直接量只有一个,不会产生多个副本。

使用new String()创建的字符串对象是运行时创建出来的,它被保存在运行时内存区内(堆内存),不会放入常量池中。

要判断两个引用变量的值是否相等时,可以使用.equals判断。equals()方法也可以重写。

类成员

Java类包含5种成员:
Field,方法,构造器,初始化块,内部类(包括接口、枚举)

类Field(static修饰)属于整个类,当系统第一次准备使用该类时,系统会为该类Field分配内存空间。类Field开始生效,直到该类被卸载,所占内存才会被垃圾回收机制回收。类Field生存范围几乎等同于该类的生存范围。当类的初始化完成后,类Field也被初始化完成。

类Field既可通过类访问,也可通过类的对象来访问。通过类的对象来访问类Field时,实际上访问的不是该类所拥有的Field。而C#其实不允许通过对象访问类Field。

单例(Singleton)类

class Singleton
{
   private static Singleton instance;
   private Singleton(){} //隐藏构造函数
   public static Singleton getInstance(){
        if(instance==null){
           instance=new Singleton();
        }
   }
}
public class SingletonTest{
   public static void main(String[] args)
   {
       Singleton s1=Singleton.getInstance();
       Singleton s2=Singleton.getInstance();
       System.out.println(s1==s2);
   }

}

final 修饰符

final类似C#里的sealed关键字,用于表示它修饰的类、方法和变量不可改变

final 成员变量

final修饰的成员变量必须由程序员显示地指定初始值
类 Field:在静态初始化块中或声明该Field时指定初始值
实例Field:必须在非静态初始化块、声明Field或构造函数中指定初始值

final 局部变量

final 修饰基本类型变量和引用类型变量的区别

final修饰基本类型变量,变量的值不能改变
但修饰引用类型变量,只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象可以发生改变。

可执行“宏替换”的final变量

对一个final变量来说,不管它是类Field、实例Field,还是局部变量,只要该变量满足3个条件,这个final变量就不再是一个变量,而是相当于一个直接量

  • 使用final修饰符修饰
  • 在定义该final变量时指定了初始值
  • 该初始值可以在编译时就被确定下来
    示例:
public class test{
  public static void main(String[] args)
  {
     final int a=5;
     System.out.println(a);
  }
}

上面所示变量a其实不存在,在编译时就转换成System.out.println(5);

Java使用常量池来管理用过的字符串直接量,如String a=”java”;
如果再定义
String b=”java”;
这时a==b 是true。

final方法

final修饰的方法不可被重写。如果不希望子类重写父类的某个方法,就可以使用final修饰该方法 。
Object类的getClass()就是一个final方法。

final 类

final修饰的类不可以有子类。如:java.lang.Math

不可变类(immutable)

创建实例后,该实例的Field是不可改变的。Java的8个包装类和java.lang.String都是不可在。
- 使用private final修饰Field
- 提供带参数构造器,用于根据传入参数来初始化类的Field
- 仅为该类的Field提供getter方法,不要为该类的Field提供setter方法
- 如果有必要,重写Object类的hashCode和equals方法。

缓存实例的不可变类

抽象类

  • 使用abstract修饰,抽象方法不能有方法体。
  • 抽象类不能被实例化,无法使用new创建实例,只能当作父类被继承
  • 抽象类可以有Field、方法、构造函数、初始化块、内部类、枚举类
  • 含有抽象方法的类只能被定义成抽象类
  • abstract不能用来修饰局部变量、构造函数
  • static 和 abstract不能共同修饰同一个方法

接口

抽象类是从多个类中抽象出来的模板,如果将这种抽象进行是更彻底,则可以提炼出一种更加特殊的抽象类——接口。接口城不能包含应运,接口城的所有方法都是抽象方法。

接口的定义

[修饰会] interface 接口中 extends 父接口1,父接口2...
{
    常量定义;
    抽象方法定义;
}

示例:

package lee;
public interface Output{
   int MAC_CACHE_LINE=50;
   void out();
   void getData(String msg);
}

接口的继承

接口完全支持多继承,一个接口可以有多个直接父接口。多个父接口排在extends后,用,隔开。

使用接口

接口不能用于创建实例,但接口中以用于声明引用类型爆裂。当使用接口为声明引用类型变量地,这个引用类型盘龙乃至其实现类的对象。除此之外,接口的主要用途不是被实现类实现。

示例:


interface Product
{
    int getProduceTime();
}

public class Printer implements Out , Product{
    private String[] printDate=new String[MAX_CACHE_LINE];
    private int dataNum=0;

    public void out(){
        while(dataNum>0){
            System.out.println("打印机打印"+printDate());
            System.arraycopy(printDate,1,printDate,0,--dataNum);
        }
    }
    public void getData(String msg){
        if(dataNum >= MAX_CACHE_LINE){
            System.out.println("输出队列已满,添加失败");
        }else
        {
            printData[dataNum++]=msg;
        }
    }
    public int getProducteTime(){
        return 45;
    }
    public static void main(String[] args){
        Output o = new Printer();
        o.getData("轻量级Java EE企业应用实战");
        o.getData("疯狂Java 讲义");
        o.out();
        o.getData("疯狂Android讲义");
        o.getData("疯狂Ajax讲义");
        o.out();
        Product p = new Printer();
        System.out.println(p.getProduceTime());
        //所有接口类型的引用变量都可直接赋给Object类型的变量
        Object obj=p;
    }
}

接口和抽象类比较

相同点
  • 接口和抽象类都不能被实例化
  • 接口 抽象类都可以包含抽象方法,初现接口或继承抽象类的普通子类都必须实现这些抽象方法
差别
  • 接口体现的是一种规范。对接口实现者而言,接口规定了实现者必须对外提供哪些服务(以方法的形式为提供);对于接口调用者而言,接口规定了调用者可以调用哪些服务,以及如何去调用这些服务。…

面向接口编程

可以实现简单工厂模式、命令模式等。

内部类

非静态内部类

public class OuterClass
{

}

静态内部类

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 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(is.a+","+is.b");
    }
}

匿名内部类

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();
            ta.test(new Product(){
                public double getPrice(){
                    return 567.8;
                }
                public String getName(){
                    return "AGP";
                }
            })
        }
    }
}

闭包和回调

闭包(Closure)是一种能被调用的对象,它保存创建它的作用域信息。Java7没有显式支持闭包,但可以把非静态内部类当成面向对象领域的闭包。
通过这种仿闭包的非静态内部类,就可以很方便地实现回调功能。

interface Teachable{
    void work();
}
public class Programmer{
    private String name;
    public Programmer(){}
    public Programmer(String name){
        this.name=name;
    }
    //...getter & setter
    public void work(){
        System.out.println(name + "doing...");
    }
}

public class TeachableProgrammer extends Programmer implements Teachable{
    public void work(){
        System.out.println(getName()+"doing ...");
    }
}

这个地方实现方式比较重要,在书籍:P211,还是直接看书时这部分描述能看得更清楚。

枚举类

public class Season
{
   private final String name;
   private final String desc;
   public static final Season SPRING=new Season("春天","");
   public static final Season SUMMBER=new Season("夏天","");
   public static final Season FALL=new Season("秋天","");
   ...
   public static Season getSeason(int seasonNum){
   switch(seasonNum){
      case 1:
         return SPRING;
      case 2:
         return SUMMBER;
      ...
   }
   }
   private Season(String name,String desc){
      this.name=name;
      this.desc=desc;
   }
   public String getName(){
      return this.name;
   }
   public String getDesc()
   {
      return this.desc();
   }
}

使用

public class SeasonTest
{
   public SeasonTest(Season s)
   {
      System.out.println(s.getName());
   }
   public static void main(String[] args)
   {
      new SeasonTest(Season.FALL);
   }
}

使用enum 枚举类

SeasonEnum.java
public enum SeasonEnum
{
   SPRING,SUMMBER,FALL,WINTER;
}
EnumTest.java
public class EnumTest
{
   public void judge(SeasonEnum s)
   {
       switch(s)
       {
             case SPRING:
                System.out.println("描述");
                break;
             ...
       }

   }
   public static void main(String[] args)   
   {
      for(SeasonEnum s:SeasonEnum.values()){
         System.out.println(s);
      }
      new EnumTest().judge(SeasonEnum.SPRING);
   }
}

java.lang.Enum类提供了以下方法:

  • int compareTo(E o)
  • String name()
  • int ordinal()
  • String toString()
  • public static

枚举类的Field,方法 和构造函数

枚举类也可以定义Field、方法。
枚举为的实例只能是枚举值,不能随意通过new创建枚举类对象。

在setName里可以对赋值进行验证。

实现接口的枚举类

枚举类也可以实现一个或多个接口。与普通类实现一个或多个接口完全一样,枚举类实现一个或多个接口时,也需要实现该接口所包含的方法。

包含抽象类的枚举类

略…

对象与垃圾回收

垃圾回收只负责回收堆内存中的对象,不会回收任何物理资源
程序无法精确控制垃圾回收的运行
垃圾回收前,会调用finalize()方法,该方法可能使该对象重新复活,从而导致垃圾回收机制取消回收

对象在内存中的状态

  • 可达状态:一个对象被创建后,若有一个以上的引用变量引用它,就处理可达状态
  • 可恢复状态:不再有变量引用,即进入了可恢复状态
  • 不可达状态:已经调用finalize()后依然没有使该对象变成可达状态

这里写图片描述

强制垃圾回收

  • 调用System.gc()静态方法
  • 调用Runtime.getRuntime().gc()实例方法

测试:


public class GcTest {
    public static void main(String[] args){
        for(int i=0;i<4;i++){
            new GcTest();
        }
    }
    public void finalize()
    {
        System.out.println("系统正在清理资源");
    }
}

可以看到finalize()不会被调用。
而如果:


public class GcTest {
    public static void main(String[] args){
        for(int i=0;i<4;i++){
            new GcTest();
            Runtime.getRuntime().gc();
        }
    }
    public void finalize()
    {
        System.out.println("系统正在清理资源");
    }
}

则finalize()会被调用。
使用java -verbose:gc GcTest查看垃圾回收后的提示信息:
这里写图片描述

但上面语句只是建议垃圾回收,系统仍有可能不立即进行垃圾回收。

finalize方法

  • 不要调动调用对象的finalize()方法
  • finalize()方法调用时间有不确定性,不要把它当成一定会被执行的方法
  • 当JVM执行可恢复对象的finalize()方法时,可能使对象或系统中其它对象重新变成可达状态
  • 当JVM执行finalize()方法出现异常时,垃圾回收机制不会报告异常,程序继续执行。

System和Runtime类提供了runFinalization方法,可以强制垃圾回收机制调用系统中可恢复对象的finalize()方法

对象的软、弱、虚引用

略…

使用JAR文件

常用命令:

创建JAR文件

jar cf test.jar test //test是目录

创建JAR文件并显示压缩过程

jar cvf test.jar test

不使用清单文件

jar cvfM test.jar test

自定义清单文件内容

jar cvfm test.jar manifest.mf test

查看jar包内容

jar tf test.jar

查看JAR包详细内容

jar tvf test.jar

解压缩

jar xf test.jar

带提示信息解压缩

jar xvf test.jar

更新JAR文件

jar uf test.jar Hello.class

更新时显示详细信息

jar uvf test.jar Hello.class

创建可执行的jar包

程序发布的方式:
- 使用平台相关的编译器,使用第三方编译器
- 为应用编辑一个批处理,如windows
java package.MainClass

start javaw package.MainClass

  • 将一个应用程序制作成可执行的JAR包,通过JAR包来发布应用程序
    jar cvfe test.jar Test *.class
    该命令把目录下的*.class压缩到test.jar,并指定使用Test类为程序入口。
    运行的方法:
    java -jar test.jar
    javaw test.jar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程圈子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值