第3章:面向对象编程


时间:2018-07-19 作者:魏文应


一、成员变量和局部变量

成员变量,也叫做 类的属性。下面代码中, agename 是声明在 类里,但在方法外 的变量,那它就叫做 类的成员变量。相对的,变量 ijn 依次是声明在 方法内、方法的形参、代码块内 的三个变量,这三种情况的变量,叫做 局部变量

class Animal{
    // 这就是属性(成员变量)
    int age;
    String name;
    
    public void setAge(int n){
        // 这就是局部变量
        int i = 0;
        
        for(int j = 0; j < 10; j++)
            i++;
        age = n;
        age += i;
    }
}

成员变量 存储在堆 中,局部变量 存储在栈 中。比如,下面代码中,Animal 对象 test 的成员变量,有age和name,分别存储在堆中,test 存储了一个地址引用,指向堆中Anima类的实体。而 i、n、j 存储在堆中:

public class TestAnimal{
    public static void main(String[] args){
        
        Animal test = new Animal();
        test.setAge(1);
    }
}
  • 成员变量和局部变量存储

局部变量 必须显式初始化,成员变量可以 不显式初始化,编译器可以给 成员变量 一下默认赋值:

数据类型 默认赋值
byte、short、int、long 0
float、double 0.0
char 空格
引用类型变量(比如String) null

成员变量可以使用 public、private、protected、缺省 修饰变量,比如:

public int age;

局部变量却不可以使用这些关键字来修饰(修饰了没有意义)。

二、类的方法

方法格式:权限修饰符 返回值类型 方法名 参数

class Animal{
    public void testPrintln(){
        System.out.println("Hello World!");
    }
}

可以在方法内 调用其它方法,但不能在方法内 定义其它方法

三、方法的重载

构成方法的重载,需要下面的条件:

  • 在同一个类中。
  • 方法名必须相同。
  • 方法的参数列表不同。
class OverLoad{
    public int getSum(int i, int j){
        return i + j;
    }
    
    public int getSum(int i, int j, int k){
        return i + j + k;
    }
    
    public double getSum(double d1, double d2){
        return d1 + d2;
    }
    
    public void getSum(double d1, double d2, double d3){
        System.out.println(d1 + d2 + d3);
    }
}

从上面可以看出,方法重载 和返回值没有关系。比如下面会 报错

class OverLoad{
    public int getSum(int i, int j){
        return i + j;
    }
    public void getSum(int i, int j){
        return i + j;
    }
}

四、匿名类对象

匿名,就是没有名字。下面代码中,TestNoName c = new TestNoName();,这个是 有名称 的类对象,名称为 cnew TestNoName().show(); 这个是 没有名称 的类对象,这就是匿名类对象。

public class PassObject {
    public static void main(String[] args) {
        TestNoName c = new TestNoName();
        new TestNoName().show();
    }
}

class TestNoName {
    public void show(){
        System.out.println("Test No Name Class");
    }
}

当我们只需 调用类对象一次,那我们就可以考虑使用匿名类对象。

五、可变形式形参的方法

方法的参数个数是可变的,可以是任意多个:0个到无穷多个。格式如下:

修饰  返回值  函数名  (参数类型 ... 参数名)

或者 使用下面格式

修饰  返回值  函数名  (参数类型[] 参数名)

比如,下面两种格式是一样的,表示一模一样的一个方法:

public void sayHello(String ... args)
public void sayHello(String[] args)

下面是一个应用示例(其实常见的 main(String[] args) 就是可变参数):

public class TestArgs {
    public static void main(String[] args) {
        new TestHello().sayHello("Hello", "World", "!");
    }
}

class TestHello{
    public void sayHello(String ... strings ){
        for(int i = 0; i < strings.length; i++){
            System.out.println(strings[i]);
        }   
    }
}

当我们有一个固定参数的时候,我们需要先把固定参数写前面,可变参数写后面。比如下面的代码,参数 i 写前面,可变参数写后面:

public void sayHello(int i, String ... strings)

六、函数参数值传递

方法参数传递中,我们可以看下面代码:

public class TestSwap {
    public static void main(String[] args) {    
        int i = 1, j = 2;
        
        TestSwap tmp = new TestSwap();
        tmp.swap(i, j);
        System.out.println("i = " + i + "; " + "j = " + j + ";");
    }
    
    public void swap(int m, int n){
        m = m ^ n;
        n = m ^ n;
        m = m ^ n;
        
        System.out.println("m = " + m + "; " + "n = " + n + ";");
    }
}

运行打印的结果显示,m 和 n 的值发生了互换,但 i 和 j 的值没有发生互换。原因是,当我们传参时 swap(i, j),栈中就会开辟新的两个内存空间,并赋值 m = i; n = j; 。从图中可以看出,i 和 j 的值 从始至终没有改变过,变化的只是 m 和 n。

  • 类方法参数传递情况

如果想要上面的 i 和 j 的值发生交换,类方法的参数应该使用 引用数据类型

public class TestArgsSwap {

    public static void main(String[] args) {
        
        DataSwap tmp = new DataSwap();
        tmp.i = 1;
        tmp.j = 2;
        
        TestArgsSwap tmp2 = new TestArgsSwap();
        
        tmp2.swap(tmp);
        System.out.println("tmp.i = " + tmp.i + "; " + "tmp.j = " + tmp.j + ";");
    }
    
    public void swap(DataSwap ds){
        ds.i = ds.i ^ ds.j;
        ds.j = ds.i ^ ds.j;
        ds.i = ds.i ^ ds.j;
        
        System.out.println("ds.i = " + ds.i + "; " + "ds.j = " + ds.j + ";");
    }
}

class DataSwap{
    int i;
    int j;
}

由于类方法参数 ds ,同样指向 tmp 类的堆内存地址,两个 引用变量指向的内存相同,所以导致最终 tmp.i 和 tmp.j 的值被修改了。

  • 使用引用数据类型的情况

七、面向对象的封装性

我们是可以 直接给成员变量赋值 的,比如,下面的代码,给类成员变量 legs 赋值:

public class TestAnimal {

    public static void main(String[] args) {
        Animal tmp = new Animal();
        
        tmp.legs = 4;
    }

}

class Animal{   
    String name;
    int legs;
}

但是,我们希望对legs的值的范围做一定的限制,那么使用类方法可以对属性进行操作:

public class TestAnimal {

    public static void main(String[] args) {
        Animal tmp = new Animal();
        
        tmp.legs = 4;
        tmp.setLegs(3);
    }

}

class Animal{   
    String name;
    int legs;
    
    public void setLegs(int n){
        if(n > 0 && n % 2 == 0){
            legs = n;
        }else{
            System.out.println("你输入的数据有误");
        }
    }
}

这时我们还是可以 在外面对 legs 成员变量 进行赋值操作,如果我们 不希望外面能够直接 对legs进行赋值操作,那么,可以在成员变量前,加上 private 私有化修饰:

public class TestAnimal {

    public static void main(String[] args) {
        Animal tmp = new Animal();
        
        // tmp.legs = 4; // 这就不可以用了。否则报错
        tmp.setLegs(3);
    }

}

class Animal{   
    String name;
    private int legs;
    
    public void setLegs(int n){
        if(n > 0 && n % 2 == 0){
            legs = n;
        }else{
            System.out.println("你输入的数据有误");
        }
    }
}

八、权限修饰符

Java权限修饰符 public、protected、private、缺省,置于类的成员定义前,用来 限定 对象对该类成员的 访问权限 。权限范围如下(yes表示可以访问):

修饰符 类内部 同一个包 子类 任何地方
private yes
(缺省) yes yes
protected yes yes yes
public yes yes yes yes

上面的四个中修饰符情况,可以修饰 类的方法类的成员。对于 class的权限修饰 只可以用 public(缺省)

  • public类可以在任意地方被访问。
  • default类只可以被同一个包内部的类访问。

九、类的成员之三:构造器

类除了属性、方法,还有 构造器(constructor 构造方法) 。它的形式如下:

class Person{
    public Person(){    
    }
}

也就是,它和 它所在的类重名 。如果没有没有在类中 显示地定义构造器,编译器会默认给一构造器。默认的构造器也就是上面 空参形式的构造器 。我们可以 自定义构造器,构造器也可以 重载

class Person{
    private String name;
    
    public Person(){
        
    }
    
    public Person(String n){
        name = n;
    }
}

十、this 关键字

this 关键字,表示 当前类。比如下面的示例,方法中的 参数变量名为name,而当前 类成员变量 也有一个变量名为name 。这个时候,同时名为name的这两个变量,就 不能区分哪个是哪个。所以就加上this修饰,用 this.name 表示成员变量 private String name 的name。

class Person{
    
    private String name;
    
    public void setName(String name){
        this.name = name;
    }
}

this 可以像上面一样修饰 成员变量,同样也可以修饰 类方法、构造器。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容