您的位置:首页 > 职场人生

黑马程序员——Java 面向对象(上)

2013-12-01 11:36 162 查看
------- android培训java培训、期待与您交流!
----------

 

Java面向对象(基础)

 

1. 面向对象

面向对象程序设计(Object Oriented Programming,OOP;Object Oriented Design,OOD)。

1.1 什么是面向对象?面向对象的三大特征?

面向对象算是一种比较新的软件设计的方法,在没有面向对象之前使用的是面向过程(是针对于一个问题解决问题,如果修改的话,则整个设计都要修改),面向对象是针对于一类问题来进行解决,某一局部的修改不影响其他位置的变化。

面向对象程序设计的三大基本特征:封装(encapsulation),继承(inheritence),多态(polymorphism)。后面逐个讲解。

封装是面向对象的方法所应遵循的一个重要原则,它有两个含义,一是指把对象的属性和行为看成一个密不可分的整体,将这两者“密封”在一个不可分割的独立单位(即对象)中;另一层含义指“信息隐藏”,把不需要让外界知道的信息隐藏起来,有些对象的属性及行为允许用户知道或使用,但不允许更改,而另一些属性或行为,则不允许外界知道,或只允许使用对象的功能,而尽可能隐藏对象的功能实现细节。封装机制在程序设计中表现为,把描述对象属性的变量及实现对象功能的方法合在一起,定义为一个程序单位,并保证外界不能任意更改其内部的属性值,也不能任意调动其内部的功能方法。封装机制的另一个特点是,为封装在整体内的变量及方法规定不同级别的“可见性”或访问权限。

继承是面向对象方法中的重要概念,并且提高软件开发效率的重要手段。首先拥有反映事物一般特征的类,然后在其基础上派生反映特殊事物的类。如已有汽车类,该类中描述了汽车的普遍行为和属性,进一步再生产轿车的类,轿车的类是继承与汽车类,轿车类不但拥有汽车类的全部属性和行为,还增加轿车特有的属性和行为。

 

在面向对象程序设计中有两个重要的概念:类(class)和对象(object)。

1.2 类与对象的关系?

类:一种抽象的概念,类中包含了数据(通常使用名词来表示)与对数据的操纵(通常使用动词来表示)。比如说“人”就是一种抽象的概念,人具有姓名、年龄、身高等数据,还有吃饭、跑步、睡觉等操纵数据的动作。

对象:是一种具体的概念,是类的一种具体表示形式。比如说人是一个类,而张三、李四、王五等具体的人就是对象。

类与对象关系:类是对象的模板,对象是类的实例,如下图:



类所包含的内容,一般类中包含两部分内容:
a).数据,数据在类中称作属性(property或attribute)或者叫成员变量(member variable)。
b).对数据的操纵,在类中称作方法(method)。

1.3 类与对象的使用

如何定义一个类?定义一个类要使用class关键字。在类中有两大部分:属性(变量)、方法。

如何定义方法?属性?  

public class Person
{
修饰符  类型  属性名称;
修饰符 返回类型  方法名称([参数1],[参数2],[参数3],[...])
{
//方法体代码
[return... //]
}
}

 

public class Person{	// 定义类
String name ;		// 表示一个人的姓名
int age ;			// 表示一个人的年龄
public void tell(){	// 表示一个功能,说话
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}


如何生成对象?通过类生成对象(通常使用new关键字来生成对象)。对象(object)又叫做实例(instance)。生成一个对象的过程又叫做实例化。

public class Person
{

}
//类名 变量名 = new 类名();
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();

Tip:main方法是整个Java程序的入口点,如果类的定义中没有main方法,则程序无法执行。命名约定(类、方法和属性)。

方法定义不能嵌套,也就是说不能在一个方法中定义另一个方法。方法只能定义在类中。关于方法的执行,首先需要定义方法,接下来就可以使用方法(调用方法),当方法调用完毕,方法可以返回值。方法到底是否返回值是由方法的定义决定的。

方法调用需要通过对象来完成,方法调用形式是:对象变量.方法名([参数1,参数2,参数3,.....]);

person1.tell();
person2.tell();
person3.tell();

关于方法的注意事项:

1).在方法定义中,方法的返回值类型与return后面的变量类型保持一致;

2).在方法调用时,给方法传递的参数需要与方法定义时的参数保持一致(参数个数一致,参数类型一致);

3).方法定义时的返回类型与接收方法返回值的变量类型保持一致。

4).方法参数传递,无论传递的是原生数据类型还是引用类型,统一是传值(pass by alue)。

public int add(int a,int b)
{
return a + b;
}
// 方法定义时参数叫做形式参数
int  c = test.add(3,5);//方法调用时赋予的具体值叫做实际参数


如果方法不返回值,那么声明方法的时候使用void关键字,在方法定义中可以有两种情况实现不返回值:

a).不使用return语句;

b).使用return,但return后面没有任何值或变量,return后面只有一个分号,表示退出方法,返回到方法的调用端。

 

属性需要定义在类中,又叫做成员变量,而定义在方法中的变量叫做局部变量。

如何使用属性?与方法一样,使用"."运算符。首先需要先生成类的实例,然后使用实例加上"."的方式来使用。比如:

Person person1 = new Person();
person1.age;


局部变量使用前必须要声明并赋初值;成员变量使用前必须要声明,但是可以不赋初值。

关于成员变量与局部变量的联系与区别:

a).无论是成员变量还是局部变量,使用前都需要声明(定义)。

b).对于局部变量来说,使用前必须要初始化;对于成员变量来说,使用前可以不初始化。如果没有初始化成员变量就开始使用,那么每个类型的成员变量都有一个默认的初始值。

 i.byte,short,int,long类型的默认初始值为0;

 ii.float,double类型的默认初始值为0.0;

iii.char类型的默认初始值为'\u0000';

 iv.boolean类型的默认初始值为flase; 

Java三大特征之一:封装(Encapsulation

一句话封装:类包含了数据与方法,将数据与方法放在一个类中就够成了封装。

1.4 对象的引用传递

引用类型(reference type):引用类型是用在对象上的,一个对象可以被对多个引用所指向,但同一时刻,每个引用只能指向唯一的一个对象。如果一个对象被多个引用所指向,那么无论哪个引用对对象的属性进行了修改,都会反映到其他的引用当中。

什么类型的引用就只能指向什么类型的对象,比如Person类型的引用就只能指向Person类型的对象,就不能指向其他类型的对象。比如:

Person person = new Person();//正确
Person person = new Student();//错误


 

如果一个类包含了属性和方法,那么该类的每一个对象都具有自己的属性,但无论一个类包含有多少个对象,这些对象共享同一个方法。

构造方法(constructor):构造方法用于完成对象的初始化工作,构造方法的特点:

a).构造方法的名字必须与类名完全一致(包含大小写);

b).构造方法没有返回值,连void也不能出现;

c).如果在定义一个类的时候,没有为类声明构造方法,那么Java编译器会自动为类添加一个没有参数且方法体为空的构造方法(默认的构造方法);

d).如果在定义一个类的时候,为类声明了构造方法,那么Java编译器就不会再为类添加构造方法了;

e).不能显式调用类的构造方法,构造方法通常是通过new关键字隐式调用。

默认的构造方法:构造方法没有参数且方法体为空。
new关键字在生成对象时完成了三件事:

a).为对象开辟内存空间

b).调用类的构造方法

c).将生成的对象的地址返回

使用 new 来生成对象的时候,后面的小括号()表示构造方法的参数列表,如果构造方法不接收参数,那么小括号中的内容为空;如果构造方法接收参数,那么小括号中的实际参数就需要与构造方法定义中的形式参数保持一致 (参数数量一致、参数类型一致、按照顺序逐一赋值)。

 

重载(overload):方法重载表示一个类中两个或多个方法名字相同,但方法参数不同。方法参数不同有两层含义:1)参数个数不同,2)参数类型不同。注意:方法的返回值对方法重载没有任何影响。

构造方法重载:只需要看参数即可。如果想在一个构造方法调用另外一个构造方法,那么就可以使用this()的方式调用,this()括号中的参数表示目标构造方法的参数。this()必须要作为构造方法的第一条语句,换句话说,this()之前不能有任何可执行代码。

this关键字:在Java中this可以做一下操作,

访问属性、调用方法(包含了构造方法)、表示当前对象。

  this访问属性

public class Person {
private String name ;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String getInfo(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
}

  this调用方法

 

public class Person {
private String name ;
private int age ;
public Person(){
System.out.println("一个新的对象产生了!") ;
}
public Person(String name){
this() ;		// 调用本类中的无参构造
this.name = name ;
}
public Person(String name,int age){
this(name) ;	// 调用有一个参数的构造
this.age = age ;
}
public String getInfo(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
}

注意使用this调用本类中其他构造方法,此语句必须要放在此构造方法的第一行。一个类中如果有多个构造方法,必须保留一个是不用this调用其他构造的情况,以作为出口,否则程序会溢出。

  this表示当前

this的最大用法实际上就只有一个:“表示当前对象”,包括以上的访问属性或者是调用构造等等,实际上都是此概念的体现。当前调用类中方法的对象称为当前对象。

class Person {
public void fun(){
System.out.println("当前对象:" + this) ;
}
}
public class Demo {
public static void main(String args[]){
Person p1 = new Person() ;
Person p2 = new Person() ;
System.out.println("p1对象:" + p1) ;
p1.fun() ;
System.out.println("--------------------------") ;
System.out.println("p2对象:" + p2) ;
p2.fun() ;
}
}


程序运行结果:

 

---------- java ----------
p1对象:Person@c17164
当前对象:Person@c17164
--------------------------
p2对象:Person@1fb8ee3
当前对象:Person@1fb8ee3


 Java三大特征之二:继承(Inheritence)

1.Java是单继承的,意味着一个类只能从另一个类继承(被继承的类叫做父类【基类 Base Class】),继承的类叫做子类,Java中的继承使用extends关键字。

现在有个Student类要继承Person类,并扩展其自身属性或行为。

class Student extends Person
{
//String name;//从父类继承
//int age;//从父类继承
String school;
String course;//课程
int score;//成绩
public double exam(String course){
//some code
return score;
}
}


分析Student类与Person的继承关系:



使用extends可以实现继承的关系,但是这个关键字的本身含义是“扩展”,更准确地说是一个类扩展已有类的功能。注意:在使用继承时,子类是不能直接访问父类中的私有成员的,子类可以调用父类的非私有方法,但是不能直接调用父类中的私有成员。

 

2.子类对象的实例化

在继承的操作中,对于子类对象的实例化也是有要求的。当生成子类对象时,Java默认首先调用父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象,没有父类对象就没有子类对象。比如说:没有父亲,就没有孩子】

class Person
{
String name;
int age;
Person(){
System.out.println("父类Person的无参构造方法。");
}
public void tell(){
System.out.println("my name is "+name);
}
}

class Student extends Person
{
String school;
String course;//课程
int score;//成绩
public Student(){
System.out.println("子类Student的无参构造方法。");
}
public double exam(String course){
//some code
return score;
}
}
public class Demo
{
public static void main(String[] args){
Student stu = new Student();
stu.name = "zhangsan";
stu.age = 30;
stu.course = "english";
System.out.println("姓名:"+stu.name+",年龄:"+stu.age+",课程:"+stu.course);
}
}

程序运行输出结果:

---------- java ----------
父类Person的无参构造方法。
子类Student的无参构造方法。
姓名:zhangsan,年龄:30,课程:english

从程序的运行结果可以清楚的发现,子类对象在实例化前会先默认调用父类中的构造方法,就好象没有父亲就没有孩子,所以在实例化子类对象前需要先将父类中属性进行初始化。对于上面的代码实际上在子类的构造方法中隐含了一个super()的语法,代码如下:

public Student(){
super();
System.out.println("子类Student的无参构造方法。");
}


如果子类使用super()显式调用父类的某个构造方法,那么在执行的时候就会寻找与super()所对应的构造方法而不会再去寻找父类不带参数的构造方法。与this()一样,super()也必须要作为构造方法的第一条执行语句,前面不能有其他可执行语句。

关于继承的几个特点:

a).父类有的,子类也有,

b).父类没有的,子类可以增加,

c).父类有的,子类可以改变。

关于继承的注意事项:

a).构造方法不能被继承;

b).方法和属性可以被继承;

c).子类的构造方法隐式地调用父类的不到参数的构造方法;

d).当父类没有不带参数的构造方法时,子类需要使用super()来显式地调用父类的构造方法,super指的是对父类的引用。super必须是构造方法中的第一行语句。

方法的重写(Override):又叫做方法的覆写。指子类与父类中同名的方法,方法返回类型一样、名字一样、参数一样,这样子类与父类的方法就构成了重写关系。在方法重写时必须要考虑到权限,即子类覆写的方法不能拥有比父类方法更加严格的访问权限。【关于访问控制权限将在后面讲到。】

//方法的重写[覆写]
class Person
{
void print(){//定义一个默认访问权限的方法
System.out.println("Person --> void print(){}");
}
}
class Student extends Person
{
public void print(){//重写父类中的方法,并扩大了权限
System.out.println("Student --> void print(){}");
}
}

当方法被重写之后,子类对象调用的将是被重写之后的方法。当两个方法形成重写关系时,可以在子类中通过super.方法名()形式调用父类的方法,其中super.方法名()不必放在第一行语句,因为此时父类对象已经构造完毕,先调用父类的方法还是先调用子类的方法是根据程序的逻辑决定的。

class Student extends Person
{
public void print(){//重写父类中的方法,并扩大了权限
super.print();//调用父类中print()方法
System.out.println("Student --> void print(){}");
}
}
关于属性的覆盖,如果子类和父类声明了相同名称的属性,则子类中直接访问时一定采用“就近访问原则”,即先找到本类中属性,如果此时要调用父类中的属性,直接使用“super.属性”即可。

关于方法的重载和方法重写的区别:



this与super的区别:



Java三大特征之三:多态(Polymorphism)

多态在面向对象中是一个最重要的概念,我们说子类就是父类(玫瑰是花,男人是人),因此多态的意思就是:父类型的引用可以指向子类的对象(Person p = new Student())。

在Java中面向对象主要有以下两种主要体现:

a).方法的重载与重写

b).对象的多态性

对于方法的重载与重写,上面已经提到过,这里主要介绍对象的多态性。而对象的多态性又分以下两种类型:

a).向上类型转换(upcast):子类对象->父类对象 (父类 父类对象 = 子类实例)

b).向下类型转换(downcast):父类对象->子类对象(子类子类实例
= (子类)父类实例)

父类Animal:

//父类Animal
class Animal
{
public void sing()
{
System.out.println("animal is singing");
}
}


子类Cat,Dog:

//子类Dog
class Dog extends Animal
{
public void sing()
{
System.out.println("dog is singing");
}
}
//子类Cat
class Cat extends Animal
{
public void sing()
{
System.out.println("cat is singing");
}
}


向上类型转换:比如说将Cat类型转换为Animal类型,即子类类型转换为父类类型,对于向上类型转换不需要显式指定。

public class Demo
{
public static void main(String[] args){
Cat cat = new Cat();
Animal animal = cat;
animal.sing();
}
}


输出运行结果:

---------- java ----------
cat is singing


向下类型转换:比如将Animal类型转换为Cat类型。即将父类型转换为子类型。对于向下类型转换,必须要显式指定(必须要使用强制类型转换)。

public class Demo
{
public static void main(String[] args){
Animal animal = new Cat();
Cat cat  = (Cat)animal;//强制转换
cat.sing();
}
}


输出运行结果:

---------- java ----------
cat is singing


总结:

1.面向对象的三大特征;

2.类与对象的关系,类的组成、对象的使用、对象引用的传递;

3.使用private关键字对属性和方法进行封装,只要是属性或方法都必须封装,封装之后的属性为其提供get和set方法;

4.当一个新对象实例化的时候要调用构造方法,构造方法名称与类名称相同,无返回值声明,而且一个类中至少保留一个构造方法,如果任何一个构造方法都没有定义的话,则会自动生成一个无参的,什么都不做的构造;

5.继承可以用来扩充已有类的功能,使用extends关键字,在Java中只允许单继承而不允许多继承,而且继承时实际上是将所有的内容都继承了下来,只是有些内容是显式继承,私有的属于隐式继承;

6.子类对象的实例化:子类对象实例化之前先去调用父类的构造方法,之后再调用子类的构造方法;

7.this和super的区别;重载及覆写的区别;

8.覆写:子类定义了一个与父类完全一样的方法,称为覆写,覆写的时候必须注意访问控制权限;

9.对象多态性。

------- android培训java培训、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息