类与对象

  

类与对象

面向过程与面向对象:

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

面向对象(OOP)的三大特征:

l  封装——把数据隐藏在对象里面,不让外部对其随意操作。

l  继承——扩展类的功能。

l  多态——方法的重载、对象的多态性

 

类:

类是组成Java程序的基本元素,它封装了一系列的变量(即数据成员,也称为“域(field)”)和方法(即成员方法 method),是一类对象的原型。创建一个新的类,就是创建一个新的数据类型。实例化一个类,就得到一个对象。因此,对象就是一组变量和相关方法的集合,其中变量表明对象的状态、属性,方法表明对象所具有的行为。

类的定义:

[修饰符]class 类名 [extends 父类名] [implements 接口名表]

{  //  类体

成员变量声明

方法成员声明

}

例、定义一个简单的Person类:

public class Person{

         String name     ;        // 表示人的姓名

         int age ;             // 表示人的年龄

         public void tell(){       // 定义说话的方法

                   System.out.println("姓名:" + name + ",年龄:" + age) ;

         } }

注意:该类中有两个属性name、age和一个方法tell().类以及定义出来了,但只有类是不能直接使用的,要实例化一个对象才可以使用.

例、实例化一个对象:

class Person{

         String name     ;        // 表示人的姓名

         int age ;             // 表示人的年龄

         public void tell(){       // 定义说话的方法

                   System.out.println("姓名:" + name + ",年龄:" + age) ;

         } }

public class Demo01{

         public static void main(String args[]){

                   Person per = new Person() ;    // 产生实例化对象per

         } }

对象产生之后,就可以调用类中的一系列操作了。

例、为Person对象中的name和age赋值,并调用tell()方法

class Person{

         String name     ;        // 表示人的姓名

         int age ;             // 表示人的年龄

         public void tell(){       // 定义说话的方法

                   System.out.println("姓名:" + name + ",年龄:" + age) ;

         }

}

public class Demo02{

         public static void main(String args[]){

                   Person  per = new Person() ; //*产生实例化对象;如果对象只声明的话,则无法

*直接使用,必须实例化后才可以正确使用。若该语句改为

*Person  per则将出现空指向异常(NullPointerException)*/

                   per.name = "张三" ;                  // 为名字赋值

                   per.age = 30 ;                     // 为年龄赋值

                   per.tell() ;                            // 调用方法

         }

}

一个类可以产生多个对象。

class Person{

       String name ;      // 表示人的姓名

       int age ;        // 表示人的年龄

       public void tell(){ // 定义说话的方法

              System.out.println("姓名:" + name + ",年龄:" + age) ;

       }

}

public class Demo03{

       public static void main(String args[]){

              Person per1 = null ;    // 声明对象

              Person per2 = null ;    // 声明对象

              per1 = new Person() ;       // 实例化对象

              per2 = new Person();

              per1.name = "张三" ;       // 为名字赋值

              per1.age = 30 ;                  // 为年龄赋值

              per2.name="李四";

              per2.age = 33 ;

              per1.tell() ;                 // 调用方法

              per2.tell() ;

       }

}

其内存划分如下图-1:

                      图-1

因为声明了两个对象,所以在栈内存空间中开辟了两个空间,保存二个对象,之后些两个对象分别实例化,只要一出现关键字new就表示开辟新的内存空间。那么这二个对象之间不会互相影响

将上例改为:

class Person{

         String name     ;        // 表示人的姓名

         int age ;             // 表示人的年龄

         public void tell(){       // 定义说话的方法

                   System.out.println("姓名:" + name + ",年龄:" + age) ;

         }

}

public class Demo04{

         public static void main(String args[]){

                   Person per1 = null ; // 声明对象

                   Person per2 = null ; // 声明对象

                   per1 = new Person() ;       // 实例化对象

                   per2 = per1 ;                       // 引用传递

                   per1.name = "张三" ;               // 为名字赋值

                   per1.age = 30 ;                            // 为年龄赋值

        per2.name="李四";

                   per2.age = 33 ;

                   per1.tell() ;                          // 输出:姓名:李四,年龄:33

                   per2.tell() ;           //同样输出:姓名:李四,年龄:33

         }

}

其过程如下图-2:

图-2

图-3

构造方法:

在每个类中都存在一个构造方法,构造方法的主要目的是为类中的属性初始化。如果在一个类中没有明确声明一个构造方法的话,则自动生成一个无参的,什么也不做的构造方法。

构造方法的名称必须与类名一致

构造方法定义时没有返回类型说明

不能在构造方法使用return语句

构造方法本身是可以进行重载操作的,重载原则与普通方法一样

如果一个类中已声明了一个构造方法,则不会生成无参什么都不做的构造方法。

例:

class Person{

       String name ;      // 表示人的姓名

       int age ;        // 表示人的年龄

       Person(String name,int age)   //声明构造方法

       {this.name=name;

        this.age=age;

       }

       public void tell(){ // 定义说话的方法

              System.out.println("姓名:" + name + ",年龄:" + age) ;

       }

}

public class Demo05{

       public static void main(String args[]){

              Person per1 = new Person("张三",30);

              Person per2 = new Person("李四",33);

              per1.tell() ;                 // 调用方法

              per2.tell() ;

       }

}

 

类的方法:

方法是一段可重复调用的代码,其定义格式:

[修饰符] [static] 返回值类型 方法名(类型 参数1,类型 参数2……)

{方法体

}

方法名的命名规范:第一个单词的首字母小写,之后每个单词的首字母大写。 

方法的重载:方法名相同,参数类型或个数不同。例:

public class Demo06

{public static int add(int a,int b)

       {return a+b;

       }

 public static int add(int a,int b,int c)

       {return a+b+c;

    }

 public static double add(double a,double b)

       {return a+b;

    }

 public static void main(String[] args)

       {int a=1,b=2,c=3;

     double d=1.5,e=2.5;

        System.out.println(add(a,b));  //输出3

        System.out.println(add(a,b,c)); //输出6

        System.out.println(add(d,e));  //输出4.0

    }

}

 

使用重载时要注意以下情况:

public class Demo07

{public static int add(int a,int b)

       {return a+b;

       }

 public static float add(int a,int b)

       {return a+b;

    }

 public static void main(String[] args)

       {

    }

}

运行后将出现以下错误:

该操作不是方法的重载,因为重载的时候,看的不是方法的返回类型,而是参数的类型或个数。

在方法的使用中,可以用return来结束一个方法的操作。

输出0~9的数字

public class Demo08

{

       public static void f(int begin, int end)

       {

              if(begin>end) return; //结束该方法

              System.out.println(begin);

              f(begin+1, end); 

       }

       public static void main(String[] args)

       {

              f(0,9);

       }

}

 

方法的递归(方法自己调用自己)

有5个人坐在一起,  问第5 个人几岁,他说比第4个人大2岁。问第4个人岁数,他说比第3 个人大2岁。问第3个人,又说比第2个人大2岁问第2个人,说比第1个人大2岁。最后再问第 1个人,他说是10岁请问第5个人几岁?

public class Demo09

{static int age(int n)

    { int c;

       if(n==1) c=10;

       else c = age(n-1)+2;

       return c ;

    }

 public static void main(String[] args)

       {

      System.out.println(age(5));

       }

}

 

类的封装:

“封装”是面向对象思想的第一大要素,封装性是类的重要特性,如果没有能体现"封装性”的类,那么面向对象的另外两大要素”实现类的继承”以及”类的多态”将成为无源之水、无本之木。

public 声明的数据成员和成员函数可从类外部的任何地方访问。

而private 数据将被隐藏,在类外不可见,这就实现了数据封装的思想。

要从类外操纵private 成员,只能通过类的public或protected成员来实现。

看以下例子。

 

 

 

class Person{

       String name ;      // 表示人的姓名

       int age ;        // 表示人的年龄

       public void tell(){ // 定义说话的方法

              System.out.println("姓名:" + name + ",年龄:" + age) ;

       }

}

public class Demo10{

       public static void main(String args[]){

              Person per = new Person() ;    // 实例化对象

              per.name = "张三" ;          // 为name属性赋值

              per.age = 30;

              per.tell() ;

       }

}

因为现在类中的所有操作都是对外部可见的,可以直接访问。可通过封装性来解决此问题,在JAVA中封装有很多的体现,但最简单的体现就是加入“private”关键字。上例改为:

class Person{

       private String name   ;      // 表示人的姓名

       private int age ;         // 表示人的年龄

       public void tell(){ // 定义说话的方法

              System.out.println("姓名:" + name + ",年龄:" + age) ;

       }

}

public class Demo11{

       public static void main(String args[]){

              Person per = new Person() ;    // 实例化对象

              per.name = "张三" ;          // 为name属性赋值

              per.age = 30;

              per.tell() ;

       }

}

运行后

name和age属性石使用private关键字声明的,所以无法在外部直接访问。证明现在的属性是安全的,可以直接保护了。但是现在的代码是安全了,知识安全过头了,都无法进行操作了。那该怎么办呢?被封装的属性可通过setter和getter方法设置和取得。如下例:

class Person{

 private String name ;      // 表示人的姓名

 private int age ;              // 表示人的年龄

 public void tell(){      // 定义说话的方法

       System.out.println("姓名:" + this.getName() + ",年龄:" + this.getAge()) ;

       }

 public void setName(String n){

       name = n ;

       }

 public void setAge(int a){

       if(a>=0&&a<=200)

              age = a ;

       }

 public String getName()

    {return name ; }

 public int getAge()

    {return age ;}

}

public class Demo12{

 public static void main(String args[]){

       Person per = new Person() ;    // 实例化对象

       per.setName("张三") ;             // 为name属性赋值

       per.setAge(-30);

       per.tell() ;

       }

}

 

 类的继承:

通过继承可以简化类的定义,扩展类的功能。

实现继承的方式:class 子类名称 extends 父类{}

class Person{

 String name      ;      // 表示人的姓名

 int age ;             // 表示人的年龄

 Person(String name,int age)

       {this.name=name;

     this.age=age;

    }

 public void tell(){      // 定义说话的方法

       System.out.println("姓名:" + name + ",年龄:" + age);

       }

}

class Student extends Person

{String id;   //学号

 Student(String id,String name,int age)

       {super(name,age);

     this.id=id;

    }

 void printId()

       {System.out.println("学号:"+id);

    }

}

public class Demo13{

 public static void main(String args[]){

    Student s=new Student("001","张三",20);

       s.printId();

       s.tell();

       }

}

JAVA只支持单继承,不允许多继承,虽然一个父类可以有多个子类,但一个子类只能有一个父类。就如,一个父亲可以有多个孩子,但一个孩子只能有一个亲身父亲。JAVA虽然不允许多继承,但可以多层继承,即:父类—子类—孙类。

继承的规定:子类只继承父类所有的公有成员和公有方法,无法继承私有的属性或方法。

class Person{

 String name      ;      // 表示人的姓名

 int age ;             // 表示人的年龄

 Person(String name,int age)

       {this.name=name;

     this.age=age;

    }

 private void tell(){    // 定义说话的方法

       System.out.println("姓名:" + name + ",年龄:" + age);

       }

}

class Student extends Person

{String id;   //学号

 Student(String id,String name,int age)

       {super(name,age);

     this.id=id;

    }

 void printId()

       {System.out.println("学号:"+id);

    }

}

public class Demo14{

 public static void main(String args[]){

    Student s=new Student("001","张三",20);

       s.printId();

       s.tell();

       }

}运行如下:

 

子类对象在实例化时,默认调用父类中无参构造方法。

class Person{

 String name      ;      // 表示人的姓名

 int age ;             // 表示人的年龄

 Person()

       {System.out.println("***父类***");}

 public void tell()       // 定义说话的方法

       {System.out.println("姓名:" + name + ",年龄:" + age);

       }

}

class Student extends Person

{String id;   //学号

 Student()

       {

        System.out.println("***子类***");

    }

 void printId()

       {System.out.println("学号:"+id);

    }

}

public class Demo15{

 public static void main(String args[])

       {new Student();}

}

运行后输出:

***父类***

***子类***

方法的覆写:

方法名称与参数要完全一样,在覆写之后子类调用的方法永远是覆写之后的方法。覆写时子类方法的权限不能比父类拥有更严格的访问权限,覆写之后的权限最好与父类中的保持一致。

class Person{

 public void tell()

       {System.out.println("***覆写前***");}

}

class Student extends Person

{ public void tell()

       {System.out.println("***覆写后***");}

}

public class Demo16{

 public static void main(String args[])

       {Student s=new Student();

        s.tell();}

}  //运行后输出:***覆写后***

多态性:

多态从字面去解释就是多种形态...

具体到语言来说,

就是一个父类派生出来的多个子类,

这些子类都继承了父类的共性,

但各自拥有自己的特性,

也就是说子类是父类的多种形态(多态)你可以通过实例化某个子类

来将对象传给父类,

让父类(共性)去完成你所实例化的字类的属性或方法(特性)。

方法的重载与覆写实际上就是属于多态的一种体现。

比如,一个父类:车;有一些子类:奔驰、宝马、欧迪……。定义一个方法fun指明车的品牌,所有子类也都有这个方法fun。

车 a=new 奔驰();

车 b=new 宝马();

车 c=new 欧迪();

a.      fun()则可得到奔驰,b.fun()则可得到宝马,c.fun()则可得到欧迪。

 

对象的多态性主要指的是,子类与父类对象的相互转换关系。

向上转型:父类名  父类对象 =子类实例

向下转型:子类名  子类对象 =(子类名)父类实例

class Car

{public void fun1()

       {System.out.println("***汽车品牌***");}

 public void fun2()

       {System.out.println("***桥车型***");}

}

class Benchi extends Car

{public void fun1() //将父类的方法覆写

       {System.out.println("***奔驰***");}

 public void fun3() //此方法为子类自己定义的,父类中不存在

       {System.out.println("车牌:粤B11223");}

}

public class Demo17

{public static void main(String[] args)

       {Car a=new Benchi();    /*发生向上转型:子类——>父类,

*父类中有的方法才可调用。如a.fun3()则会报错,父类中无fun3()方法*/

        a.fun1(); //输出:***奔驰***

        a.fun2(); //输出:***桥车型***

       }

}

 

 

 

 

如果想调用fun3()的方法则应发生向下转型的关系

class Car

{public void fun1()

       {System.out.println("汽车品牌");}

 public void fun2()

       {System.out.println("桥车型");}

}

class Benchi extends Car

{public void fun1() //将父类的方法覆写

       {System.out.println("***奔驰***");}

 public void fun3() //此方法为子类自己定义的,父类中不存在

       {System.out.println("车牌:粤B11223");}

}

public class Demo18

{public static void main(String[] args)

       {Car a=new Benchi();  /*发生向上转型:子类——>父类,此句若改为:

              *Car a=new Benchi()则会出现以下异常:

              *Exception in thread "main" java.lang.ClassCastException:

              *A cannot be cast to B*/

        Benchi b=(Benchi)a; //发生向下转型(强制)

        b.fun1();  //输出:***奔驰***

        b.fun2();  //输出:***桥车型***

        b.fun3();  //输出:车牌:粤B11223

       }

}

 

设计一个方法,可以接收Car类的所有子类的实例。

class Car

{public void fun1()

       {System.out.println("汽车品牌");}

 public void fun2()

       {System.out.println("桥车型");}

}

class Benchi extends Car

{public void fun1() //将父类的方法覆写

       {System.out.println("***奔驰***");}

 public void fun3() //此方法为子类自己定义的,父类中不存在

       {System.out.println("车牌:粤B11223");}

}

class Baoma extends Car

{public void fun1()

       {System.out.println("***宝马***");}

 public void fun4()

       {System.out.println("车牌:粤B44556");}

}

public class Demo19

{public static void main(String[] args)

       {fun(new Benchi());

        fun(new Baoma());

       }

 public static void fun(Benchi bc)

       { bc.fun1();

     bc.fun3();

    }

 public static void fun(Baoma bm)

       { bm.fun1();

     bm.fun4();

    }

}

以上方式是通过方法的重载完成的,存在以下缺点。若Car类有10000个子类则须重载10000次。而且在每次增加子类时都须修改代码本身。所以此时用对象的多态性就可以很好的解决此类问题。因为所有的对象都会发生自动的向上转型。

class Car

{public void fun1()

       {System.out.println("汽车品牌");}

 public void fun2()

       {System.out.println("桥车型");}

}

class Benchi extends Car

{public void fun1() //将父类的方法覆写

       {System.out.println("***奔驰***");}

 public void fun3() //此方法为子类自己定义的,父类中不存在

       {System.out.println("车牌:粤B11223");}

}

class Baoma extends Car

{public void fun1()

       {System.out.println("***宝马***");}

 public void fun4()

       {System.out.println("车牌:粤B44556");}

}

public class Demo20

{public static void main(String[] args)

       {fun(new Benchi());

        fun(new Baoma());

       }

 public static void fun(Car c)

       {c.fun1();}

}

但以上操作依然 存在一些问题,无法调用子类中自己定义的方法(父类不存在的方法)。且各个子类的方法又不尽相同,若要调用谋个子类的方法,则先判断所属那个子类。JAVA中提供了instanceof关键字完成这样的功能。

格式:对象 instanceof 类      // 返回boolean类型的数据,true或false。

class Car

{public void fun1()

       {System.out.println("汽车品牌");}

 public void fun2()

       {System.out.println("桥车型");}

}

class Benchi extends Car

{public void fun1() //将父类的方法覆写

       {System.out.println("***奔驰***");}

 public void fun3() //此方法为子类自己定义的,父类中不存在

       {System.out.println("车牌:粤B11223");}

}

class Baoma extends Car

{public void fun1()

       {System.out.println("***宝马***");}

 public void fun4()

       {System.out.println("车牌:粤B44556");}

}

public class Demo21

{public static void main(String[] args)

       {fun(new Benchi());

        fun(new Baoma());

       }

 public static void fun(Car c)

       {c.fun1();

     if(c instanceof Benchi)

              {Benchi bc=(Benchi)c;

               bc.fun3();}

        if(c instanceof Baoma)

              {Baoma bm=(Baoma)c;

               bm.fun4();}

    }

}

运行后输出:

***奔驰***

车牌:粤B11223

***宝马***

车牌:粤B44556

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值