黑马程序员_java面向对象

------------- java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

 

 

 

面向对象的三大特征:封装  (Encapsulation),继承  (Inheritance),多态  (Polymorphism)

比较两个数组对象的内容是否相等可以使用Arrays.equals()方法;

模块设计追求强内聚(许多功能尽量在类的内部独立完成,不让外面干预),弱耦合(提供给外部尽量少的方法调用)。

每个成员方法内部,都有一个this引用变量,指向调用这个方法的对象。

System.gc(); 调用 gc 方法暗示着 Java 虚拟机做了一些努力来回收未用对象,以便能够快速地重用这些对象当前占用的内存。
调用 System.gc() 实际上等效于调用: Runtime.getRuntime().gc()。
对象被回收之前会调用对象的finalize()方法,此方法是Object类的方法,子类可以重写。

Object类中有一个clone()方法,可以获取对象的一份拷贝,返回类型是Object对象。
如果一个类的对象需要支持拷贝(或者是克隆),那么这个类就需要实现Cloneable接口,然后需要重写clone()方法,并在该方法里面调用super.clone();
public Object clone() throws CloneNotSupportedException {
 return super.clone();
}
         注意:拷贝对象中的变量时,对于引用类型的变量,拷贝的是引用地址,我们也可以对该引用所代表的类进行支持拷贝。
Cloneable接口是标识接口,里面没有声明任何方法。

为什么我们要在派生类中覆盖Object类中的clone()方法时,一定要调用super.clone()呢?
因为在运行时刻,Object中的clone()方法会自动识别出你要复制的是那一个对象,然后为此对象分配空间,并进行对象的复制,
将原始对象中的数据一一复制到新对象的存储空间中。

对于更深层一些的拷贝见如下例子:
package com.heima.exam;

public class CloneableTest {

/**
       * @param args
      */
 public static void main(String[] args) throws Exception {
  // TODO Auto-generated method stub

  Professor professor = new Professor("教授1");
         CloneAttachment catt0 = new CloneAttachment("zhangsan", 20, professor);
         CloneAttachment catt1 = (CloneAttachment) catt0.clone();
           catt1.name = "lisi";
           catt1.age = 30;
           catt1.profe.name = "教授2";
  
           System.out.println(catt0);
           System.out.println(catt1);
 }

}

class CloneAttachment implements Cloneable {
          String name;
          int age;
          Professor profe;
 
 public CloneAttachment(String name, int age, Professor profe) {
           this.name = name;
           this.age = age;
           this.profe = profe;
 }
 
 public Object clone() throws CloneNotSupportedException {
           CloneAttachment camt = (CloneAttachment) super.clone();
           camt.profe = (Professor) profe.clone();
           return camt;
 }
 
 public String toString() {
           return name + ":" + age + ":" + profe.name;
 }
}

class Professor implements Cloneable {
          String name;
          public Professor(String name) {
           this.name = name;
 }
 public Object clone() throws CloneNotSupportedException {
          return super.clone();
 }
}


如果一个类的对象需要被排序,例如:A[] aArr = new A[] {...}; Arrays.stor(aArr);
那么A类必须实现Comparable接口,并且重写compareTo(Object obj)方法。如:
public int compareTo(Object o) {
           A a = (A)o;
           int retVal = 1;
           if(this.age < a.age) {
           retVal = -1
 }
           return  retVal;
}

对已经进行过排序处理(Arrays.sort())的数组,我们可以用Arrays.binarySearch(...)方法来对数组进行搜索,返回一个数组索引值。

当一个程序中用到了其他的类,类是在第一次被使用的时候才被加载,而不是在程序启动时就加载程序中所有可能要用到的类。
一个类被加载的时候会执行类的静态代码块。static {...}

单态设计模式。
       如下是饱汉模式:
package com.heima.exam;

public class Singleton {

 private static final Singleton singleton = new Singleton();
 
 private Singleton() {}
 
 public static Singleton getInstance() {
            return singleton;
 }
}

如下是饥汉模式:
package com.heima.exam;

public class Singleton {

 private static Singleton singleton = null;
 
 private Singleton() {}
 
 public static Singleton getInstance() {
  if(singleton == null) {
             singleton = new Singleton();
  }
            return singleton;
 }
}


          嵌套类可以直接访问嵌套它的类的成员,包括private成员,但是嵌套类的成员却不能被嵌套它的类直接访问。

一个内部类,不管它嵌套有多深,都可以访问外部类的所有成员。

在内部类对象保存了一个对外部类对象的引用(Outer.this),当内部类的成员方法中访问某一变量时,如果在该方法和内部类中都没有定义过这个变量,内部类中对this的引用会被传递给那个外部类对象的引用。(即:this.变量不存在的情况下,传递给Outer.this.变量)

如果用static修饰一个内部类,这个类就相当于是一个外部定义的类,所以static的内部类中可声明static成员,
但是,非static的内部类中的成员是不能声明为static的。static的内部类不能再使用外层封装类的非static的成员变量

内部类也可以是abstract类,也可以是final类。

内部类如何被外部引用:如下例子说明。
class Outer
{
     private int size=10;
     public class Inner
     {
      public void doStuff()
      {
          System.out.println(++size);
      }
     }
}
public class TestInner
{
 public static void main( String[] args)
 {
            Outer outer = new Outer();
            Outer.Inner inner = outer.new Inner();
            inner.doStuff();
 }
}


在类的外部需要派生内部类子类的程序代码如下:
package com.heima.exam;

public class NewInClassOverOutClass {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
            C c = new C(new A());
            c.sayHello();
 }

}

class A {
 
 class B {
  public void sayHello() {
             System.out.println("hello");
  }
 }
}

class C extends A.B {
 
 public C(A a) {
  a.super();
  /* 因为要产生一个派生类的对象时,会调用基类的构造函数,
   * 由于基类是内部类,所以首先要产生外部类对象,才能产生内部类对象,
   * 从而建立起内部类对象到外部类对象的引用关系。*/
 }
}


          嵌套类并非只能在类里定义,也可以在几个程序块的范围之内定义内部类。例如,在方法中,或甚至在for循环体内部,都可以定义嵌套类 。
          在方法中定义的内部类只能访问方法中的final类型的局部变量,用final定义的局部变量相当于是一个常量,它的生命周期超出方法运行的生命周期。

使用Java的文档注释:文档注释以“/**”开始,以“*/”标志结束,相应的信息和批注所对应的位置很重要! 类的说明应在类定义之前,方法的说明应在方法的定义之前。
批注参数来标记一些特殊的属性及其相应的说明 。
@author<作者姓名>
@version<版本信息>
@param<参数名称><参数说明>
@return<返回值说明>

 

子类继承父类所有的成员变量和成员方法,但不继承父类的构造方法。在子类的构造方法中可使用语句super(参数列表) 调用父类的构造方法。

如果子类的构造方法中没有显式地调用父类构造方法(super(...)),也没有使用this关键字调用重载的其它构造方法,
则在产生子类的实例对象时,系统默认调用父类无参数的构造方法。

子类对象的实例化过程:
1,分配成员变量的存储空间并进行默认的初始化,就是用new关键字产生对象后,对类中的成员变量按第三章的表3.1中的对应关系对对象中的成员变量进行初始化赋值;
2,绑定构造方法参数,就是new Person(实际参数列表)中所传递进的参数赋值给构造方法中的形式参数变量;
3,如有this()调用,则调用相应的重载构造方法(被调用的重载构造方法又从步骤2开始执行这些流程),被调用的重载构造方法的执行流程结束后,
   回到当前构造方法,当前构造方法直接跳转到步骤6执行;
4,显式或隐式追溯调用父类的构造方法(一直到Object类为止,Object是所有Java类的最顶层父类,在本章后面部分有详细讲解),
   父类的构造方法又从步骤2开始对父类执行这些流程,父类的构造方法的执行流程结束后,回到当前构造方法,当前构造方法继续往下执行;
5,进行实例变量的显式初始化操作,也就是执行在定义成员变量时就对其进行赋值的语句;
6,执行当前构造方法的方法体中的程序代码。

覆盖(重写)(Override)父类的方法:(三同,更宽,更小,更少)
       覆盖方法必须和被覆盖方法具有相同的方法名称、参数列表和返回值类型;
       覆盖方法时,不能使用比父类中被覆盖的方法更严格的访问权限;
       必须扔出父类方法抛出的相同的异常或异常的子类,或者不抛出异常;
       必须扔出父类方法抛出的那些异常的一个子集,也就是说不能扔出新的异常。
       如果在子类中想调用父类中的那个被覆盖的方法,我们可以用super.方法的格式。

 

方法重载(Overload):重载的方法,参数列表必须不相同(参数个数不同、参数类型不同、参数顺序不同,只要满足其一就表示参数列表不同。)
其他无任何规定,重载的方法可以是返回值不同的,但是参数列表必须不相同。可以看如下例子:

package com.heima.exam;

public class OverloadTest {
 
 public void method() {
         System.out.println("无参数方法");
 }
 
 public void method(String str) {
         System.out.println("一个String类型的参数为:" + str);
 }
 
 public void method(int i) {
         System.out.println("一个int类型的参数为:" + i);
 }
 /*
  * 如下的重载方法是不合法的。因为参数列表跟上面的方法是一样的
  * 只是返回值不同,那不能构成方法的重载。
  * 但是只要参数列表不同了,那么返回值可以是任何类型,都是合法的重载方法。
 public int method(int i) {
         return i;
 }
 */

 public void method(int i, String str) {
         System.out.println("两个参数,分别为int类型, String类型的参数为:" + i + ":" + str);
 }
 
 public void method(String str, int i) {
         System.out.println("两个参数,分别为String, int类型的参数为:" + str + ":" + i);
 }
 
 public int method(int i, int j) {
         return i + j;
 }
 
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
         OverloadTest olt = new OverloadTest();
         olt.method();
         olt.method("hello");
         olt.method(999);
         olt.method(8, "haha");
         olt.method("haha", 9);
         System.out.println(olt.method(5, 15));
 }

}

 

在Java中,传递参数时,都是以传值的方式进行传递。
       对于基本数据类型:传递数据的拷贝;
       对于引用类型:传递引用地址的拷贝。

 


       在Java中声明类、属性和方法时,可使用关键字final来修饰。
       final标记的类不能被继承。
       final标记的方法不能被子类重写。
       final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。
       方法中定义的内置类只能访问该方法内的final类型的局部变量,用final定义的局部变量相当于是一个常量,它的生命周期超出方法运行的生命周期,将一个形参定义成final也是可以的,这就限定了我们在方法中修改形式参数的值。 
       public static final共同标记常量时,这个常量就成了全局的常量。
       为了节约内存,我们一般情况下都把声明为final的变量同时也用static修饰。
       因为声明为static的变量为类成员变量,不用为每个产生的实例对象做一份拷贝。
       final变量一般在声明时初始化,也可以在构造函数中初始化。


抽象类和抽象方法用abstract关键字修饰。


       声明为native的方法是本地方法,其中需要用到JNI(java native interface),JNI是Java和本地应用程序的中介。还需要用到javah命令生成类的头文件。
本地方法的主要目的是利用本地资源扩展Java功能,而与Java本身的机制无关。
       一个本地方法如同一个抽象方法,并没有实际的方法体,因为本地方法的实现不是Java语言,而是采用依赖本地平台的其他语言编写的位于Java虚拟机之外的函数库中,可以通过System.loadLibrary()方法装入。System.loadLibrary()通常放置在静态初始化代码中。如果本地方法没有装载成功,则抛出UnsatisfiedLinkError异常。

对本地方法的调用和Java中的其他方法一样的调用,本地方法的实现对调用者是透明的。实际上,在Object类上定义的clone()方法和notify()方法就是本地方法。


接口是抽象方法和常量值的定义的集合

接口中的成员都是public访问类型的。
接口中的变量默认是用public static final标识的 。所以接口中的变量在其实现类中可以直接访问,也可以通过其实现类的实例去访问。
       接口中的方法默认是用public abstract 修饰的。所以实现接口中的方法的时候需要声明为public的。

我们也可以定义一个类用implements关键字去实现一个接口中的所有方法,我们还可以去定义一个抽象类用implements关键字去实现一个接口中定义的部分方法。

一个接口可以继承自另一个接口,而且接口可以是多继承。如:
       interface Sofa extends Sittable, Lie {}


       instanceof 操作符可以用它来判断一个实例对象是否属于某一个类。


       运行时异常(RuntimeException)如:ArithmeticException, NullPointerException, IndexOutOfBoundsException等之类的异常可以不用显式的捕获或者抛出。

如果我们编写的一个方法中有可能发生异常,那么就应该在方法后面声明要抛出异常,用“throws <异常类1,异常类2,...>”。

异常有很多种,我们可以编写自己的异常类,这个类必须继承Exception类。

在程序中需要抛出自定义的异常,用throw关键字。

finally语句块始终都会被执行,除非在try或catch中执行了System.exit(0);

小技巧:利用异常的处理机制,我们可以在一个方法中使用throw,try…catch语句来实现程序的跳转。

类本身只能有两种访问控制符(内部类除外)public修饰的类能被所有的类访问,默认修饰(即class关键字前没有访问控制符)的类,只能被同一包中的所有类访问。

类成员中的访问控制修饰符有:
       private:   同一类
       (缺省):    同一类,同一包中的类
       protected: 同一类,同一包中的类,子类
       public:    所有类

jar –cvf  (打包)
       jar –tvf  (查看包内容)
       jar –xvf  (解压包)
       jar –tvf  >a.txt   (查看包内容,把查看结果输出到一个文件里面)

 

  

你可能感兴趣的:(java基础)