Java 面向对象入门

来源:互联网 发布:淘宝的淘口令怎么取消 编辑:程序博客网 时间:2024/05/23 21:16

面向对象入门


@Author:云都小生


span {color: red;}
p {style=”font-size:22}


类与对象



现实生活中有各式各样的对象,有狗有猫有人,有树有花有草,我们所见到的东西,都是对象。这些对象有一些,拥有相同的属性和方法。例如说狗,它们同样有四条腿,两个眼睛,它们同样都会叫 Java是面向对象的编程语言,在Java中怎么实现面向对象编程呢?

public class Test{    public static void main(String[] args)    {        Dog dog = new Dog;    }}//不同的类文件public class Dog {    String color;    String name;    String sex;    Dog(String color,String name,String sex){   //构造方法        this.color = color;        this.name = name;        this.sex = sex;    }    void run()    {        System.out.print("Dog in running···\n");    }    void bray()    {        System.out.print("汪汪汪\n");    }}

在这个例子中,Dog就是一个类,在Dog里面有这么几个属性:color、name、sex,还有三个方法。一个是Dog的构造方法,另外两个方法是run和bray。

类与对象有什么关系,有什么区别?类其实就是一个模版,对象是根据这个模版创建出来的实例。对象创建之后,自动拥有类的所有属性和方法。类并不是实际存在的,对象才是在内存中实际存在的。new这个关键字,就是用来分配内存空间。一句话理解,类就是“人”,而对象是具体的“什么样的人”。

什么是构造方法?每个类都会有构造方法,我们可以通过构造方法,一开始就给对象里面的属性赋值。如果你没有构造方法,默认的就会有一个构造方法,就像这样 Dog(){} 构造方法可以被重载。可以看下面重载的相关知识点。

Dog(String name){}

this是一个关键字,这个this算是一个指针,指向对象本身。通过构造方法传进来的那

我们可以通过对象.属性的方式,来索引对象内部的属性。Dog.name 或者 Dog.sex

对象与对象变量这里还需要谈一个小细节,对象是在内存里面实实在在存在的,而对象变量,只是一个变量,指向内存中具体对象的数据。


引用类型的内存分析


之前我们经常用String类型,其实String是一个引用类型,什么意思呢?有过指针知识基础的人应该知道,如果你不知道,莫慌。String变量其实存储的并不是真正的字符串,而是字符串在内存中存在的地址。

程序占用内存的是有不同类型的:是堆、栈、全局区、常量区、程序代码区;


1. 堆一般由程序员分配;

2. 栈一般由编译器自动分配,存放参数值,局部变量的值等;

3. 全局变量和静态变量存放的地方;

4. 常量字符串存放的地方;

5. 程序代码区。


String str = “Cloudking”; 这个str其实是存放在栈,而字符串是存放再堆里面,str会存储字符串在内存常量区的地址,通过这个地址找到相应的数据。

而在类与对象中,也是这样。对象名存储的是整个对象数据在堆中的首地址,通过这个地址去索引相应的数据。Dog dog = new Dog(); dog会指向对象数据在堆中的地址。


面向对象基本特性——重载



同一个类里面,多个方法可以有相同的名字,只要它们的参数列表不同就可以,这种方式叫“方法重载”。

public class Dog {        void printTest()        {            System.out.println("没有参数");        }        void printTest(String name)        {            System.out.println(name);        }        void printTest(int id,String name)        {            System.out.print(id + "\n" + name);        }}#main方法里面Dog dog = new Dog();dog.printTest("Cloudking");dog.printTest(123,"Cloudking");

编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法。还有几点需要注意:

· 构造方法也可以重载;

· 方法名称必须相同,才能够重载;

· 重载的方法除了方法名外,参数不能一模一样;

· 不能用返回值来进行重载。


面向对象基本特性——静态域与静态方法


静态域又称为类变量,所有的对象,都共享这一个类变量,修饰类变量的方法,就是用static,看实例。

public class Dog {        private static int id;}

这样一来,所有由Dog new出来的对象,都指向这同一个变量id。静态方法,就是不能对对象进行操作的方法。一般用到静态方法,都有两点:

  1. 方法不需要访问对象状态;
    1. 只需要访问类的静态域。

    public class Dog {
    private static double x = 8.888;

    private static void Test(){    System.out.println(getX());}public static double getX() {    return x;}public static void setX(double x) {    Dog.x = x;}

    }

    //main
    Dog dog1 = new Dog();
    Dog dog2 = new Dog();
    dog1.setX(12);
    System.out.println(Dog.getX());

还有一个小插曲,关于静态常量,我们用final来修饰常量,用static来修饰它是一个静态的常量。

public class Math{      ...      public static final double PI = 3.14159265358979323846;      ...  }  

本来加上final就修饰成常量了,再加上static,就不用每次都需要new一个对象才能使用这个常量。


面向对象特性——封装


面向对象的第一大特性——封装。这个词我们并不陌生,在面向对象中,封装指的是将细节包装、隐藏起来,防止该类的代码和数据被外部类定义的代码随机访问。这样一来,可以使代码变得安全(可靠)、更容易维护(重用性)。

以下把优点列出来:

1.  良好的封装能够减少耦合;<br/>2.  类内部的结构可以自由修改;<br/>3.  可以对成员变量进行更精确的控制;<br/>4.  隐藏信息,实现细节。<br/>

怎么对类中的属性进行封装呢?把类的属性设置为私有,对外提供“构造器”和“访问器”。

public class Dog {    private String color;    private String name;    private String sex;    Dog(String color,String name,String sex){   //构造方法        this.color = color;        this.name = name;        this.sex = sex;    }    void run()    {        System.out.print("Dog in running···\n");    }    void bray()    {        System.out.print("汪汪汪\n");    }}

把类中的属性,都加上private这个权限修饰符,就会变成类私有的属性。如果你在该类的外部去访问、修改,就会出现错误。这样一来,我们就实现了属性隐藏,那怎么才能间接性的访问、修改它们。这里就涉及到了访问器和修改器,它们能让我们间接的访问、修改类中隐藏的属性。

public class Dog {        private int id;        private String name;        Dog(int id,String name)        {            this.id = id;            this.name = name;        }        public String getname()        {            return this.name;        }        public int getid()        {            return this.id;        }        public void setname(String name)        {            this.name = name;        }        public void setid(int id)        {            this.id = id;        }}

看看这个类,把内部的属性用private隐藏了起来,通过private修饰的属性和方法,都只能在类内部被访问、修改,不能被外部直接访问(get)、修改(set)。这样做有什么好处呢?第一点,安全性,第二点,屏蔽细节

如果用户在设置数值的时候随意输,你要怎么办?你要在哪里检查?我们来看一个set方法。

public void setid(int id){    if( id <= 100 && id >= 1)    {        this.id = id;    }    else    {        System.out.println("输入有误!");    }}

类内部的方法也可以被private修饰,被private修饰的方法,只能在类内部被使用。


面向对象特性——继承



动物界中存在这么一种情况,儿子往往会继承父母的优点,就像我们,我们有可能就继承了自己父母的许多特性。而在面向对象编程中,也有这么一个特性——继承。在Java中,类与类之间可以有继承的关系,子类可以继承父类的属性和方法。

public class Animal {    String color;    void bray()    {        System.out.println("bray~");    }}public class eatgrassAnimal extends Animal {    void eat()    {        System.out.println("eat grass");    }}#maineatgrassAnimal d = new eatgrassAnimal();d.color = "yellow";d.bray();d.eat();

eatgrassAnimal从Animal类里继承,自动拥有了Animal类非private的属性和方法,它也可以拥有自己的属性和方法,作为对父类的扩展,继承可以增加程序的复用性。extends关键字用来修饰一个类从另一类中继承,Java中所有的类默认都从Object类继承。

java里只支持单继承,一个子类只能有一个父类,但是可以进行继承,简答的说,A可以从B继承,B可以从C继承,一代更比一代强。子类中如果想访问父类里面的对象,可以使用super的关键字。

public class Animal {    String color;    Animal(String color)    {        this.color = color;    }    void bray()    {        System.out.println("bray~");    }}public class eatgrassAnimal extends Animal{    String name;    eatgrassAnimal(String color,String name) {        super(color);        this.name = name;    }    void eat()    {        System.out.println("eat grass");    }    void bray()    {        super.bray();        System.out.println("eatgrassAnimal bray~");    }}#maineatgrassAnimal e = new eatgrassAnimal("yellow","羊");e.bray();

super可以调用父类的构造方法、调用父类的方法(当子类覆盖父类的方法时)、访问父类的数据域。

每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。

super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。子类覆盖或重写了父类的方法,则只有使用 super 才能在子类中调用父类中的被重写的方法。


从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。


面向对象特性——多态



由于有了继承,就延伸出了另一种特性——多态。多个子类都从同一个父类继承,像食草动物、食肉动物,都是继承自动物。在我们在编写程序的过程中,并不知道什么时候会传过来食草动物的对象、什么时候会传过来食肉动物的对象,所以我们在调用方法的时候,总不能直接就对单一的对象进行处理吧。

假设食草动物、食肉动物都有同一个方法——run(),但是在我们在调用它们这个方法的时候,需要传入不同的对象,根据不同的对象去调用它们各自的run()方法。这个就是动态绑定,根据传入的对象,去调用属于它们各自的方法。

public class eatgrassAnimal extends Animal{    void eat()    {        System.out.println("eat grass");    }}public class eatmeatAnimal extends Animal {    void eat()    {        System.out.println("eat meat");    }}public class Animal {    void eat()    {        System.out.println("eat···");    }}public class Test{    public static void main(String[] args)    {        eatgrassAnimal g = new eatgrassAnimal();        eatmeatAnimal m = new eatmeatAnimal();        print(g);        print(m);    }    static void print(Animal a)    {        a.eat();    }}

可以看到两个类eatgrassAnimal和eatmeatAnimal都是从Animal继承,都重写了Animal的eat()方法。当我们想根据传入的对象,调用它们具体的方法时,就可以写成pritn(Animal),父类引用指向子类对象。


多态的实现必须有三个条件:

1. 继承

2. 方法重写

3. 父类引用指向子类对象

现实中其实有很多多态的例子,我们能在word文档里面使用的快捷键,换到了桌口下面,也能使用快捷键,只是做出的反应不一样。

在游戏设计中,也会有多态设计的例子,例如说坦克和飞机,都是攻击性的机器,它们都有这样一个方法attack(攻击),但是它们攻击的方式都不一样,也就是方法里面实现的不一样。这样,调用attack()方法,我们就可以利用多态来实现。

public class Machine {    void attack()    {        System.out.println("Attack中···");    }}public class Aircraft extends Machine {    void attack()    {        System.out.println("战机导弹发射!");    }}public class Tanke extends Machine {    void attack()    {        System.out.println("坦克炮弹发射!");    }}public class Test{    public static void main(String[] args)    {        Tanke t = new Tanke();        Aircraft a = new Aircraft();        Attack(t);        Attack(a);    }    static void Attack(Machine m)    {        m.attack();    }}


面向对象特性——抽象类


抽象类和一般的类没有太大的区别,只是多了个抽象方法。类中有一部分不能确定——既需要这种功能,又没办法去定义主题,就可以写成抽象类。

抽象方法和抽象类都必须被abstract关键字修饰。抽象类中的抽象方法要被使用,必须由子类重写所有的抽象方法后才能调用。记住,是重写,不是纯粹的把代码复制,那样依旧是一个抽象类。

abstract class Test {    abstract void test();}

这个Test抽象类,可以实现其他的很多方法,但是这里面只要有一个抽象方法,就必须被修饰成抽象类。并且,这类还不能被final修饰,抽象类就是要继承,然后让子类去实现抽象方法,其次,方法也不能被static和private修饰。static关键字会把方法修饰成公用,即使没有对象也能直接用,那样就没有意义了,如果是private,抽象方法就不能被子类继承了。

归根结底,当一个类里面有一些不被确定的方法时,就可以使用abstact来修饰,让它成为抽象类,然后让子类去实现这个抽象方法。


面向对象特性——接口


接口不是类,而是对类的一组需求描述。Java没有提供多继承的机制,没有办法同时继承两个类,但是Java却可以实现多个接口。一个接口只有方法的特征,而没有方法的实现,因此这些方法在不同的地方被实现时,可以具有完全不同的行为。(是不是感觉跟抽象类很像)

在Java中使用interface来定义一个接口,而使用implements来实现接口。

public interface Test{   public static final int num; //成员常量具有固定的修饰符:public static final   public abstract void method; //成员函数具有固定的修饰符:public abstract }public class Testimpl implements Test{// 实现接口中的所有方法    .....}

接口的确跟抽象类很像,但是它本质上并不是类,而且,接口与接口之间可以是继承关系,而且可以实现多继承。接口比抽象类更抽象。

2017/9/2 22:52:38 @Author:云都小生

原创粉丝点击