Chinaunix首页 | 论坛 | 博客
  • 博客访问: 426290
  • 博文数量: 83
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 790
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-23 11:34
文章存档

2010年(1)

2008年(2)

2007年(24)

2006年(18)

2005年(38)

我的朋友

分类: Java

2005-07-25 11:48:09

以下是我最近一个月学习的一些感悟!!发上来是为了防止自己硬盘挂掉的话,还能找到原来有多菜的证据:)

final   @修饰的变量
           类中声明为final的变量,有两种初始化方式:1。声明时就初始化。2。在类的构造方法中初始化
            初始化以后就不能在修改了
         @修饰的方法
            不能被子类重写,但可以被本类方法重载

以下是我最近一个月学习的一些感悟!!发上来是为了防止自己硬盘挂掉的话,还能找到原来有多菜的证据:)

final           @修饰的变量
                   类中声明为final的变量,有两种初始化方式:1。声明时就初始化。2。在类的构造方法中初始化
                   初始化以后就不能在修改了
                @修饰的方法
                  不能被子类重写,但可以被本类方法重载
                @修饰类
                   我不会继承这个类, 
static         @修饰的变量
                   类中声明为static的变量,在类的第一次实例化就存在于内存,以后的实例化就不会重复产生内存空间了
                @修饰的方法
                  只能操作本类的静态成员属性

static final  @共同声明的成员属性,在申明时就要初始化

public         @类中的成员属性
                     可以被包内包外的的类的实例化对象方法使用(类A中有public方法,类B和A在同一包中,类B通过在自己的实例化对象的方法中在申明类A的对象对类A的方 法                 进行调用)
protected    @类中的成员属性
                    可以被包外继承本类的类的实例化对象使用和包内的类的实例化对象方法使用
private       @类中的成员属性
                    只能被本类的成员方法使用
interface     @
                    功能的集合,但方法都没有实体,默认都是public 方法和默认的public final 属性
abstract       @
                    本身不能被实例化,但继承它的子类在实例化自己的时候会初始化一些抽象类的属性
多态            @
                   继承了同一接口的不同类
                   在声明时声明成接口类型,在实例化时可以实例化成这几个不同类(但实例化后的对象只能使用接口本身的方法)
继承         @
                     子类可以继承父类的全部protected和public的方法和属性
  例子:
  com.org.bluedot包中一个类
  public class A
{
 protected int age;
}
com.org.bluedot.test包中一个类

import com.org.buledot.*;
public class B extends A
{
 public static void main(String [] args)
 {
  B b = new B();
  b.age;  //可以这样引用
  A a = new A();
  a.age;  //不可以这样引用
}
}


protected类型的成员属性和方法只能有本包内的方法操作和外包的子类对象操作(外包子类中new的父类对象不能操作父类的protected)
内部类            @
                      内部类的实例化发生于外部类已被实例化以后
                        可有两种实例方法1。在外部类实例化以后,用实例化的对象(My1.MyIn2 a = a0.new MyIn2();)在实例化内部对象
                                               2。在外部类的方法中加入实例化内部类。
                       内部类和外部类可以互相操作对方的private的成员属性和成员方法,不用this可直接操作,但在内部类前加上static后,内部类就不能访问外部类的属性了
                      内部类之间可以继承
                        内部类的public,private,protected修饰符同外部类的属性定义权限一样!
                       public的内部类可以被实例化了外部类的所有类实例化
                       private的内部类只能被本类的对象实例化
                       protected的内部类能被本包中实例化了外部类的所有类实例化和外包中继承了该外部类的实例化对象实例化
                      内部类隐藏的是它的类型!
                       @例子
  
class My1
{
 // 帮助类,工具类,辅助类
 private class MyIn
 {
  private int m;
  public void f()
  {
   a++;  //可访问外部
   System.out.println("MyIn...f");
  }
 }
 
 private class MyIn3 extends MyIn
 {
  public void f()
  {
   super.f();
   System.out.println("MyIn3 ... ...");
  }
 }
 
 //复杂内部类
 public class MyIn2
 {
  public void f()
  {
   a++;  //可访问外部
   System.out.println("MyIn...f");
  }
 }
 
 public static class MyIn4
 {
  //a++;  // 没有外部对象的指针
  public void f()
  {
   System.out.println("MyIn4...f");
  }
 }
 
 private int a;
 
 public void add()
 {
  a++;
 }
 
 public void show()
 {
  System.out.println(a);
  MyIn x = new MyIn();
  x.f();
  x.m++;  //外部可访问内部类
 }
 
 public void g()
 {
  //MyIn a = new MyIn3();
  //a.f();
  
  // 只用一次的类不需要定义
  MyIn x = new MyIn() {
   public void f(){
    super.f();
    System.out.println("Ni Ming");
   }
  };
  x.f();
 }
}

public class InnerC
{
 public static void main(String av[])
 {
  /*
  My1 a = new My1();
  a.add();
  a.show();
  a.show();
  */
  
  /*
  My1 a0 = new My1();
  //My1.MyIn2 a = new My1.MyIn2(); 经典错误
  My1.MyIn2 a = a0.new MyIn2();
  a.f();
  */
  
  My1 a = new My1();
  a.g();
 }
}
存储                @
                     类在实例化后,成员属性放在堆中,方法中的局部变量放在栈中
  
合成                 @
                    在新的类里面直接创建旧的类的对象,新的类是由旧的类合成而来,所复用的是代码的功能,不是代码的形式 
toString()          @
                       由一个对象调用,返回一个字符串!如果默认则使用由Object继承下来的toString(),返回这个对象的内存地址
                            Object.toString()方法内容:return getClass().getName() + "@" + Integer.toHexString(hashCode());
一个典型的重写toString()的例子:
public static String toString(int [] a)
{
 StringBuffer result = new StringBuffer("[");
 for(int i=0;i)
   Quiotix Corp首席顾问
   2003 年 8 月

   每个Java对象都有hashCode()和 equals()方法。许多类忽略(Override)这些方法的缺省实施,以在对象实例之间提供更深层次的语义可比性。在Java理念和实践这一部分,Java开发人员Brian Goetz向您介绍在创建Java类以有效和准确定义hashCode()和equals()时应遵循的规则和指南。您可以在讨论论坛与作者和其它读者一同探讨您对本文的看法。(您还可以点击本文顶部或底部的讨论进入论坛。)

   虽然Java语言不直接支持关联数组 -- 可以使用任何对象作为一个索引的数组 -- 但在根Object类中使用hashCode()方法明确表示期望广泛使用HashMap(及其前辈Hashtable)。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式中支持散列可以促进基于散列的容器的开发和使用。

定义对象的相等性

   Object类有两种方法来推断对象的标识:equals()和hashCode()。一般来说,如果您忽略了其中一种,您必须同时忽略这两种,因为两者之间有必须维持的至关重要的关系。特殊情况是根据equals() 方法,如果两个对象是相等的,它们必须有相同的hashCode()值(尽管这通常不是真的)。

   特定类的equals()的语义在Implementer的左侧定义;定义对特定类来说equals()意味着什么是其设计工作的一部分。Object提供的缺省实施简单引用下面等式:

   public boolean equals(Object obj) { return (this == obj); }

   在这种缺省实施情况下,只有它们引用真正同一个对象时这两个引用才是相等的。同样,Object提供的hashCode()的缺省实施通过将对象的内存地址对映于一个整数值来生成。由于在某些架构上,地址空间大于int值的范围,两个不同的对象有相同的hashCode()是可能的。如果您忽略了hashCode(),您仍旧可以使用System.identityHashCode()方法来接入这类缺省值。

忽略 equals() -- 简单实例

   缺省情况下,equals()和hashCode()基于标识的实施是合理的,但对于某些类来说,它们希望放宽等式的定义。例如,Integer类定义equals() 与下面类似:

   public boolean equals(Object obj) {
   return (obj instanceof Integer
   && intValue() == ((Integer) obj).intValue());
   }

   在这个定义中,只有在包含相同的整数值的情况下这两个Integer对象是相等的。结合将不可修改的Integer,这使得使用Integer作为HashMap中的关键字是切实可行的。这种基于值的Equal方法可以由Java类库中的所有原始封装类使用,如Integer、Float、Character和Boolean以及String(如果两个String对象包含相同顺序的字符,那它们是相等的)。由于这些类都是不可修改的并且可以实施hashCode()和equals(),它们都可以做为很好的散列关键字。

为什么忽略 equals()和hashCode()?

   如果Integer不忽略equals() 和 hashCode()情况又将如何?如果我们从未在HashMap或其它基于散列的集合中使用Integer作为关键字的话,什么也不会发生。但是,如果我们在HashMap中使用这类Integer对象作为关键字,我们将不能够可靠地检索相关的值,除非我们在get()调用中使用与put()调用中极其类似的Integer实例。这要求确保在我们的整个程序中,只能使用对应于特定整数值的Integer对象的一个实例。不用说,这种方法极不方便而且错误频频。

   Object的interface contract要求如果根据 equals()两个对象是相等的,那么它们必须有相同的hashCode()值。当其识别能力整个包含在equals()中时,为什么我们的根对象类需要hashCode()?hashCode()方法纯粹用于提高效率。Java平台设计人员预计到了典型Java应用程序中基于散列的集合类(Collection Class)的重要性--如Hashtable、HashMap和HashSet,并且使用equals()与许多对象进行比较在计算方面非常昂贵。使所有Java对象都能够支持 hashCode()并结合使用基于散列的集合,可以实现有效的存储和检索。

实施equals()和hashCode()的需求

   实施equals()和 hashCode()有一些限制,Object文件中列举出了这些限制。特别是equals()方法必须显示以下属性:

   Symmetry:两个引用,a和 b,a.equals(b) if and only if b.equals(a)
   Reflexivity:所有非空引用, a.equals(a)
   Transitivity:If a.equals(b) and b.equals(c), then a.equals(c)
   Consistency with hashCode():两个相等的对象必须有相同的hashCode()值

   Object的规范中并没有明确要求equals()和 hashCode() 必须一致 -- 它们的结果在随后的调用中将是相同的,假设“不改变对象相等性比较中使用的任何信息。”这听起来象“计算的结果将不改变,除非实际情况如此。”这一模糊声明通常解释为相等性和散列值计算应是对象的可确定性功能,而不是其它。

对象相等性意味着什么?

   人们很容易满足Object类规范对equals() 和 hashCode() 的要求。决定是否和如何忽略equals()除了判断以外,还要求其它。在简单的不可修值类中,如Integer(事实上是几乎所有不可修改的类),选择相当明显 -- 相等性应基于基本对象状态的相等性。在Integer情况下,对象的唯一状态是基本的整数值。

   对于可修改对象来说,答案并不总是如此清楚。equals() 和hashCode() 是否应基于对象的标识(象缺省实施)或对象的状态(象Integer和String)?没有简单的答案 -- 它取决于类的计划使用。对于象List和Map这样的容器来说,人们对此争论不已。Java类库中的大多数类,包括容器类,错误出现在根据对象状态来提供equals()和hashCode()实施。

   如果对象的hashCode()值可以基于其状态进行更改,那么当使用这类对象作为基于散列的集合中的关键字时我们必须注意,确保当它们用于作为散列关键字时,我们并不允许更改它们的状态。所有基于散列的集合假设,当对象的散列值用于作为集合中的关键字时它不会改变。如果当关键字在集合中时它的散列代码被更改,那么将产生一些不可预测和容易混淆的结果。实践过程中这通常不是问题 -- 我们并不经常使用象List这样的可修改对象做为HashMap中的关键字。

   一个简单的可修改类的例子是Point,它根据状态来定义equals()和hashCode()。如果两个Point 对象引用相同的(x, y)座标,Point的散列值来源于x和y座标值的IEEE 754-bit表示,那么它们是相等的。

   对于比较复杂的类来说,equals()和hashCode()的行为可能甚至受到superclass或interface的影响。例如,List接口要求如果并且只有另一个对象是List,而且它们有相同顺序的相同的Elements(由Element上的Object.equals() 定义),List对象等于另一个对象。hashCode()的需求更特殊--list的hashCode()值必须符合以下计算:

   hashCode = 1;
   Iterator i = list.iterator();
   while (i.hasNext()) {
   Object obj = i.next();
   hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
   }

   不仅仅散列值取决于list的内容,而且还规定了结合各个Element的散列值的特殊算法。(String类规定类似的算法用于计算String的散列值。)

编写自己的equals()和hashCode()方法

   忽略缺省的equals()方法比较简单,但如果不违反对称(Symmetry)或传递性(Transitivity)需求,忽略已经忽略的equals() 方法极其棘手。当忽略equals()时,您应该总是在equals()中包括一些Javadoc注释,以帮助那些希望能够正确扩展您的类的用户。

   作为一个简单的例子,考虑以下类:

   class A {
   final B someNonNullField;
   C someOtherField;
   int someNonStateField;
   }

   我们应如何编写该类的equals()的方法?这种方法适用于许多情况:

   public boolean equals(Object other) {
   // Not strictly necessary, but often a good optimization
   if (this == other)
   return true;
   if (!(other instanceof A))
   return false;
   A otherA = (A) other;
   return
   (someNonNullField.equals(otherA.someNonNullField))
   && ((someOtherField == null)
   ? otherA.someOtherField == null
   : someOtherField.equals(otherA.someOtherField)));
   }

   现在我们定义了equals(),我们必须以统一的方法来定义hashCode()。一种统一但并不总是有效的定义hashCode()的方法如下:

   public int hashCode() { return 0; }

   这种方法将生成大量的条目并显著降低HashMaps的性能,但它符合规范。一个更合理的hashCode()实施应该是这样:

   public int hashCode() {
   int hash = 1;
   hash = hash * 31 + someNonNullField.hashCode();
   hash = hash * 31
   + (someOtherField == null ? 0 : someOtherField.hashCode());
   return hash;
   }

   注意:这两种实施都降低了类状态字段的equals()或hashCode()方法一定比例的计算能力。根据您使用的类,您可能希望降低superclass的equals()或hashCode()功能一部分计算能力。对于原始字段来说,在相关的封装类中有helper功能,可以帮助创建散列值,如Float.floatToIntBits。

   编写一个完美的equals()方法是不现实的。通常,当扩展一个自身忽略了equals()的instantiable类时,忽略equals()是不切实际的,而且编写将被忽略的equals()方法(如在抽象类中)不同于为具体类编写equals()方法。关于实例以及说明的更详细信息请参阅Effective Java Programming Language Guide, Item 7 (参考资料) 。

有待改进?

   将散列法构建到Java类库的根对象类中是一种非常明智的设计折衷方法 -- 它使使用基于散列的容器变得如此简单和高效。但是,人们对Java类库中的散列算法和对象相等性的方法和实施提出了许多批评。java.util中基于散列的容器非常方便和简便易用,但可能不适用于需要非常高性能的应用程序。虽然其中大部分将不会改变,但当您设计严重依赖于基于散列的容器效率的应用程序时必须考虑这些因素,它们包括:

   太小的散列范围。使用int而不是long作为hashCode()的返回类型增加了散列冲突的几率。

   糟糕的散列值分配。短strings和小型integers的散列值是它们自己的小整数,接近于其它“邻近”对象的散列值。一个循规导矩(Well-behaved)的散列函数将在该散列范围内更均匀地分配散列值。

   无定义的散列操作。虽然某些类,如String和List,定义了将其Element的散列值结合到一个散列值中使用的散列算法,但语言规范不定义将多个对象的散列值结合到新散列值中的任何批准的方法。我们在前面编写自己的equals()和hashCode()方法中讨论的List、String或实例类A使用的诀窍都很简单,但算术上还远远不够完美。类库不提供任何散列算法的方便实施,它可以简化更先进的hashCode()实施的创建。

   当扩展已经忽略了equals()的 instantiable类时很难编写equals()。当扩展已经忽略了equals()的 instantiable类时,定义equals()的“显而易见的”方式都不能满足equals()方法的对称或传递性需求。这意味着当忽略equals()时,您必须了解您正在扩展的类的结构和实施详细信息,甚至需要暴露基本类中的机密字段,它违反了面向对象的设计的原则。

结束语

   通过统一定义equals()和hashCode(),您可以提升类作为基于散列的集合中的关键字的使用性。有两种方法来定义对象的相等性和散列值:基于标识,它是Object提供的缺省方法;基于状态,它要求忽略equals()和hashCode()。当对象的状态更改时如果对象的散列值发生变化,确信当状态作为散列关键字使用时您不允许更更改其状态。

Throwable                 @
                              分为Exception , Error(内存错误,栈益处)
Exception                 @
                             分为RuntimeException(java编译器不强制其和它的派生类抛出异常)(编译器认为不会犯这种错误),和checkedException(java编译器强制其抛出异  常)
java.util.Arrays          @包括一组可用于数组的static方法,其中基本方法是:1。用来比较两个数组是否相等的equals()2。用来填充数组的fill()3。用来对数组进   行排序的                          sort()4。用于在一个已排序的数组中查找元素的binarySearch()5。用于接受一个数组,然后把它转化成一个List容器
Thread.join()              @
                                  调用此函数的线程是相对于主线程的.主线程只有在调用这个函数的线程结束后,才能执行
                                 int.class == Integer.TYPE @true
总结
各种类型直接转换
String.split("@",0) @位置不能是"+"得改写成"[+]",正则表达式!!!!!!!!!!!!!!

java中的参数传递全部都是COPY,都是传值的,没有传地址的

通过内部类可是实现多重继承

阅读(1168) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~