java面向对象知识(上)

类的内部封装了方法,用于操作自身的成员。类是对某种对象的定义,具有行为(be-havior),它描述一个对象能够做什么以及做的方法(method),它们是可以对这个对象进行操作的程序和过程。它包含有关对象行为方式的信息,包括它的名称、方法、属性和事件。
类的构成包括数据成员和成员函数。数据成员对应类的属性,类的数据成员也是一种数据类型,并不需要分配内存。成员函数则用于操作类的各项属性,是一个类具有的特有的操作,比如“学生”可以“上课”,而“水果”则不能。类和外界发生交互的操作称为接口。
 
定义一个类:
 
1
2
3
4
5
6
7
8
9
10
11
class类名
{
 
public:
公有成员
private:
私有成员
 
protected:
保护成员
};
 

private:只有这个类的成员变量和成员函数可以访问,这个限制是针对类的,而不是针对对象的。

public:其他类也可以访问

friendly:同一个包内可以相互访问

public,protected,friendly,private的访问权限如下:
 
    关键字       当前类      包内      子孙类      包外 
 
    public         √                 √            √                √ 
 
    protected   √                 √             √               × 
 
    friendly       √                 √             ×               × 
 
    private        √                 ×             ×               × 
 
    不写时默认为friendly
    不使用关键字默认为包内使用。
 
若是一个类前面加了public,则说明任何人都可以用这个类的定义来定义变量。但要求这个类所处的源代码的文件名和这个类的名字相同。
编译单元:一个.java文件就是一个编译单元,指的是一次编译一个文件。
当一个编译单元里有不止一个类时,只有一个类可以作为public,其他的类因此就只能这个文件中起作用了。
 

当你的程序越来越大的时候,你就会需要有一个机制帮助你管理一个工程中众多的类了。包就是Java的类库管理机制,它借助文件系统的目录来管理类库,一个包就是一个目录,一个包内的所有的类必须放在一个目录下,那个目录的名字必须是包的名字。
 
一个包中所有的源代码第一行一定有“package xxx”,来表明它属于这个包。
当使用其他包里边的类的定义时要先“import packagename.filename”进来,其实每一个“.”就相当于文件目录中的"/"
 

static

称static定义的变量为类变量,而不是成员变量。任何对象都拥有这个变量,但是这个变量只有一份。

static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。

但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:

在上面的代码中,由于print2方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在main方法中有下面一条语句:

MyObject.print2();

此时对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。

而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。

因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。

总而言之, static函数只能访问static函数或者变量,非static函数则没有限制
 

容器

所谓容器,就是“放东西的东西”。数组可以看作是一种容器,但是数组的元素个数一旦确定就无法改变,这在实际使用中是很大的不足。一般意义上的容器,是指具有自动增长容量能力的存放数据的一种数据结构。在面向对象语言中,这种数据结构本身表达为一个对象。所以才有“放东西的东西”的说法。

ArrayList<String>是一个类,意思是ArrayList of String,即用来存放ArrayList(容器的类型)的String(元素的类型),是泛型类,也叫容器类。

ArrayList<String> notes = new ArrayList<String>();

对象数组

String[ ]表示对象数组,其中的每个元素是对象的管理者而非对象本身。
当数组的元素的类型是类的时候,数组的每一个元素其实只是对象的管理者而不是对象本身。因此,仅仅创建数组并没有创建其中的每一个对象。
public Value(){
  private int i = 0;
  public void set(int i){this.i=i;}
  public int get(){return i;}
public static void main(String[ ] args){
  Value[ ] a = new Value[10]; //创建长度为10的对象数组
  for(int i=0;i<a.length;i++){
    a[i] = new Value();      //创建对象数组中的每一个对象
    a[i].set(i);                    //给每个对象赋值
  }
  for(Value v:a){
    System.out.println(v.get());  //获取对象数组中的每一个对象,并且获得它所指向的值
  }
}

 集合容器Set

 HashSet<String> s = new HashSet<String>();
 s.add("first");
 s.add("second");
 s.add("first");
 for(String k:s){
   System.out.println(s);  //得到的结果是second,first,没有重复的元素
 }
 
容器也可以通过System.out.println(s)直接输出
在类中加入如下代码:
public String toString(){return ""+i;}
可以让System.out.println()直接输出内容。
 

 Hash表

 放在Hash表中的内容为<key, value>,在容器里边所有的类型都必须是对象,因此int是不行的,应当用Integer(Integer是int的包裹类型)。

  public class Coin(){
  private HashMap<Integer, String> coinnames = new HashMap<Integer, String>(); 
  public Coin(){
    coinnames.put(1,"penny");
    coinnames.put(10,"dime");
    coinnames.put(25,"quarter");
    coinnames.put(50,"half-dolar");
  }
  public String getName(int amount){
    return coinnames.get(amount);
  }
 }
 
遍历hash表:
for(Integer k:coinnames.keySet()){
  String s = coinnames.get(k);
  System.out.println(s);
}

 

继承

基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是public还是private。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。显然,通过继承来定义新的类,远比从头开始写一个新的类要简单快捷和方便。继承是支持代码重用的重要手段之一。
 

我们把用来做基础派生其它类的那个类叫做父类、超类或者基类,而派生出来的新类叫做子类。Java用关键字extends表示这种继承/派生关系:

  1. class ThisClass extends SuperClass { 
  2.     //…
  3. }

继承表达了一种is-a关系,就是说,子类的对象可以被看作是父类的对象。比如鸡是从鸟派生出来的,因此任何一只都可以被称作是一只鸟。但是反过来不行,有些鸟是鸡,但并不是所有的鸟都是鸡。如果你设计的继承关系,导致当你试图把一个子类的对象看作是父类的对象时显然很不合逻辑,比如你让鸡类从水果类得到继承,然后你试图说:这只本鸡是一种水果,所以这本鸡煲就像水果色拉。这显然不合逻辑,如果出现这样的问题,那就说明你的类的关系的设计是不正确的。Java的继承只允许单继承,即一个类只能有一个父类。

对理解继承来说,最重要的事情是,知道哪些东西被继承了,或者说,子类从父类那里得到了什么。答案是:所有的东西,所有的父类的成员,包括变量和方法,都成为了子类的成员,除了构造方法。构造方法是父类所独有的,因为它们的名字就是类的名字,所以父类的构造方法在子类中不存在。除此之外,子类继承得到了父类所有的成员。

但是得到不等于可以随便使用。每个成员有不同的访问属性,子类继承得到了父类所有的成员,但是不同的访问属性使得子类在使用这些成员时有所不同:有些父类的成员直接成为子类的对外的界面,有些则被深深地隐藏起来,即使子类自己也不能直接访问。下表列出了不同访问属性的父类成员在子类中的访问属性:

 

父类成员访问属性

在父类中的含义

在子类中的含义

public

对所有人开放

对所有人开放

protected

只有包内其它类、自己和子类可以访问

只有包内其它类、自己和子类可以访问

缺省

只有包内其它类可以访问

如果子类与父类在同一个包内:只有包内其它类可以访问

否则:相当于private,不能访问

private

只有自己可以访问

不能访问

public的成员直接成为子类的public的成员,protected的成员也直接成为子类的protected的成员。Java的protected的意思是包内和子类可访问,所以它比缺省的访问属性要宽一些。而对于父类的缺省的未定义访问属性的成员来说,他们是在父类所在的包内可见,如果子类不属于父类的包,那么在子类里面,这些缺省属性的成员和private的成员是一样的:不可见。父类的private的成员在子类里仍然是存在的,只是子类中不能直接访问。我们不可以在子类中重新定义继承得到的成员的访问属性。如果我们试图重新定义一个在父类中已经存在的成员变量,那么我们是在定义一个与父类的成员变量完全无关的变量,在子类中我们可以访问这个定义在子类中的变量,在父类的方法中访问父类的那个。尽管它们同名但是互不影响。

在构造一个子类的对象时,父类的构造方法也是会被调用的,而且父类的构造方法在子类的构造方法之前被调用。在程序运行过程中,子类对象的一部分空间存放的是父类对象。因为子类从父类得到继承,在子类对象初始化过程中可能会使用到父类的成员。所以父类的空间正是要先被初始化的,然后子类的空间才得到初始化。在这个过程中,如果父类的构造方法需要参数,如何传递参数就很重要了。

 

猜你喜欢

转载自www.cnblogs.com/bl8ck/p/9459717.html
今日推荐