Java 面向对象入门

面向对象入门


@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");
    }
}

#main
eatgrassAnimal 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~");
    }
}

#main
eatgrassAnimal 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:云都小生

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值