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

黑马程序员----面向对象及其三大特性

2015-08-15 15:18 429 查看
——- android培训java培训、期待与您交流! ———-

一、面向对象

面向过程:强调动作,

面向对象:只要找到对象,对象的所有功能也都找到了。

1.面向对象的形象化解释(人开门:名词提炼法)



{

  开门(门)

  {

      门.开;

  }

}



{

  开(){对门的操作}

}

2.面向对象有三个特征:封装,继承,多态。

  (以后的开发就是找对象使用,没有对象,就创建一个对象;找对象,建立对象,使用对象,维护对象的关系;) 

3.类和对象的关系:

        类:就是对现实生活中事物的描述;

        对象:就是这类事物,实实在在存在的个体(通过new操作符产生的一个实体,这个实体在堆内存当中);

        描述和对象的关系:

        现实生活中的对象:张三,李四;

        想要描述:提取对象中共性内容,对具体的抽象

        描述时:这些对象的共性有,姓名,年龄,性别,学习java的功能;

        映射到java中,描述就是class定义的类;

        具体对象就是对应java在堆内存中用new建立的实体。

        //描述一个汽车:描述事物的属性和功能;

        //属性对应的是类中的变量,行为对应的是类中的函数(方法);

        //定义类就是在描述事物,就是在定义属性和行为,属性和行为共同成为类中的成员(成员变量和成员函数);

       讲到对象,要试着画图,图画出来了,很多流程就能明白,在内存中是什么样子了

4.成员变量和局部变量的不同:

      1)作用范围不一样:成员变量作用于整个类中,局部变量作用于函数中或者语句中;

      2)在内存中的位置不一样:成员变量在堆内存中(因为对象的存在,才在内存中存在),局部变量存在栈内存中。

class Car
{
//描述颜色;
String color="红色";//显示初始化值。
//描述轮胎数
int num=4;//默认为0;

//运行行为:
void run()
{
Ststem.out.println(color+"...."+num);
}
//此类中一般不写主函数,一个程序有一个主函数就可以;
/*public static void main(String[] args)
{
Car c=new Car();//在本类中创建对象,

c.color="blue";//如果不赋值,则默认为null。

run();
}*/
}

class CarDemo
{
public static void main(String[] args)
{
//生产汽车,在java中通过new操作符来完成,其实就是在堆内存中产生一个实体
Car c=new Car();//c就是一个类类型变量,引用型变量,类类型变量指向对象。
//将已有的车的颜色改成蓝色,指挥该对象做使用,在java指挥方式是:对象.对象成员;
c.color="blue";//重新赋值;
c.run();

Car c1=new Car();
c1.run();//red 4;
}
}

二、匿名对象

Car c=new Car();

c.num=5;

上面两句代码可以简写为:new Car().num=5;

匿名对象和有名对象到底有什么不同?

    匿名对象不断地在堆中创建对象,但是当创建后一个对象是,前一个对象就已经是垃圾了,没有人再用了(前一个对象一执行完就是垃圾了)。匿名对象调用的属性没有意义,但调用的方法是有意义的。

匿名对象使用方式一:当对象的方法只调用一次时,可以用匿名对象来完成;如果对一个对象进行多个成员调用,必须给这个对象起个名字。

匿名对象使用方法二:可以将匿名对象作为实际参数进行传递。

          保证对象的生命周期到底有多长,如果不指定,虚拟机直接回收,但有些对象虚拟机不收,会一直在,那么就让该对象指向null;当做缓存技术的时候,就需要考虑到这个对象必须要把空间释放出来的时候,就需要注意强引用、弱引用、软引用、虚引用(用于优化内存,具体方法:直接用Java提供的对象就行)。

三、构造函数

        特点:
            函数名与类名相同;
            不用定义返回值类型(与void不同);
            可以不写return语句。
        作用:给对象进行初始化,对象一创建,就会调用与之对应的构造函数。
        注意:
                默认构造函数的特点:空参数;
                多个构造函数是以重载的形式存在的。

        什么时候定义构造函数呢?
                当分析事物时,该事物具备一些特性或者行为,那么将这些内容定义在构造函数中;
                确定是否有未知变量参与运算以确定参数。  

        构造函数的一个小细节:
                当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数:
Person(){}  //方便初始化;
                当自己定义了构造函数时,系统就不再添加默认构造函数;      

        构造函数和一般函数的不同:
                1.格式不同
                2.在运行上不同:
        构造函数是在对象一建立就运行,给对象初始化;而一般方法是对象调用才执行,是给对象添加对象具备的功能。 一个对象一建立,构造函数只运行一次,而一般方法可以被该对象调用多次。

四、封装(Encapsulation)

指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
好处:将变化隔离;便于使用;提高重用性; 提高安全性。
封装原则:1)将不需要对外提供的内容都隐藏起来; 2)把属性都隐藏,提供公共方法对其访问。

权限关键字:Public:公有(权限最大)Private:私有(权限最小),私有只在本类中有效,私有仅仅是封装的一种表现形式;
权限修饰符,用于修饰类中的成员(成员变量,成员函数);

一个成员变量,通常都会对应两个访问方式:set和get。
凡是set打头的方法,它的返回值类型一定是void,并且需要带参数;而get打头的方法的返回值类型跟它获取的变量类型一致,不带参数。
但凡看到一个类中有getXxx或者是setXxx,就代表这个类中一定有私有属性。
之所以对外提供访问方式,是因为可以在访问方式中加入逻辑判断等语句,对访问方式的数据进行操作,提高代码的健壮性。

五、继承(Extends)

事物关系中的一种。

1.提高了代码的复用性;

2.继承让类与类之间产生了关系,有了关系才有了多态的特性;

注意:千万不要为了获取其他类的功能,简化代码而继承;

必须是类与类之间有所属关系才可以继承,所属关系; 类1 is a 类2;当继承出现以后,子父类之间到底会发生什么样的变化?或者说,有什么样的特点了呢? 类中成员包括三个:

 1.变量;如果子父类中出现非私有的同名成员变量时,子类要访问本类中的同名变量用this,子类要访问父类中的同名变量时用super。

 this和super的使用方法基本一致。this代表的是子类对象的引用;super代表的是父类对象的引用;

 

 2.函数;当子类继承了父类,沿袭了父类的功能到子类中,但是子类虽然具备该功能而功能的内容与父类不一致时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义并重写功能内容。(功能扩展)
3.构造函数。构造函数不能重写(构造函数随着类名走,子父类函数名不能一致)。

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类构造函数的第一条执行语句默认为super();

super();会访问父类中的空参数的构造函数;而且子类中所有的构造函数默认第一行都是super();

子类必然能够访问到父类中的构造函数(默认构造函数)。

class Telephone
{
void show()
{
System.out.println("number");
}
}
class NEWTelephone
{
void show()
{
//System.out.println("number");
super.show();//父类已经定义好了,直接拿过来用;
System.out.println("name");
System.out.println("picture");
}
}

覆盖注意事项:

 1.子类覆盖父类,必须保证子类权限大于等于父类,否则编译失败;

 2.静态只能覆盖静态(一般不用,知道就行,关系到先后加载的问题)

 3.子类必须知道父类的功能才可以覆盖。

 

 重载和重写的区别:

 重载只看同名函数的参数列表,而重写叫做子父类方法要一模一样,包括返回值类型也要一样。

为什么子类一定要访问父类中的构造函数;

因为子类在对象初始化时要先访问一下父类中的构造函数。

如果要访问父类中指定的构造函数,可以通过手动定义super语句来访问。
class Person //extends Object(所有类的父类)
{
String name;
Person(String name)
{
//super();父类中也有super语句。父类继承自object。
this.name=name;
}

}
class Student extends Person
{
Student(String name)
{
super(name);//必须写在首句;
}
}

super();//必须写在子类的首句;(先找父类)

子类中this();和super();不能同时存在。    

子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。

子类中至少会有一个构造函数会访问父类中的构造函数。
class Extends //父类
{
int num=4;

void show1()
{

System.out.println("父类 show");
}
void speak()
{

System.out.println("vb");
}

Extends()//构造函数的函数名要和类名一致;
{
num=60;
System.out.println("Father run");
}
Extends(int x)//构造函数的函数名要和类名一致;
{
System.out.println("Father run"+x);
}
}

//演示变量;
class Extends_1 extends Extends //子类1
{
int num2=5;
int num=5;//当父类和子类的变量同名是,打印的是子类变量的值;
void show()
{
System.out.println(this.num);//打印子类中的num1;this代表的是子类对象的引用;
System.out.println(super.num);//打印父类中的num1;super代表的是父类对象的引用;
System.out.println(this.num);//当子类中没有自己的num变量时,this和super为同一指向,都是指向父类中的num,所以打印结果为4;
}
}

//演示函数;
class Extends_2 extends Extends //子类2
{
void show2()
{

System.out.println("子类 show");
}
void speak()//如果子父类方法名一致,会运行子类函数的内容,这就是函数的另一个特性:覆盖(重写)。父类方法没有运行。
{

System.out.println("java");
}
}

//演示构造函数;
class Extends_3 extends Extends //子类3
{
Extends_3()//函数名要和类名一致;
{
//super();//调用父类构造函数,不写虚拟机会自动加,父类构造函数中的内容会先执行;

System.out.println("child run");
}
Extends_3(int x)//函数名要和类名一致;
{
//super();
super(3);//手动指定要访问父类中的哪一个构造函数;
//this();//调用本类空参数的构造函数;
System.out.println("child2 run"+x);
}
}

public class ExtendsDemo2
{
public static void main(String[] args)//主函数;
{
//演示变量;
Extends_1 z=new Extends_1();
System.out.println(z.num+"....."+z.num2 );
z.show();

//演示函数;
Extends_2 z1=new Extends_2();
z1.show1();//打印父类 show,因为子类已经拿到了父类中的内容;
z1.show2();
z1.speak();

//演示构造函数;
Extends_3 z2=new Extends_3();
Extends_3 z3=new Extends_3(4);//传入参数;
System.out.println(z2.num);
}
}

六、多态

多态:某一类事物的多种存在形态。

对象多态性两个体现:

    人:男人;女人。

    动物:猫;狗。

    猫 x=new 猫();

    动物 x=new 猫();

围绕四个问题学习:

1.多态的表现形式?

    父类的引用指向了自己的子类对象;父类的引用也可以接受自己的子类对象;

2.多态的前提?

    必须是类与类之间有关系,要么继承,要么实现;

    存在覆盖(子类覆盖父类功能)。

3.多态到底有什么好处?

    多态的出现大大的提高了程序的扩展性;

    (弊端:只能使用父类的引用访问父类中的成员。)

4.多态如何应用?

5.多态在代码中的特点(多态使用的注意事项)

//动物体系:
abstract class Animals //父类
{
abstract void eat();//吃什么不确定;
}

class Cat extends Animals
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchmouse()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animals
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanjia()
{
System.out.println("看家");
}
}
class Pig extends Animals
{
public void eat()
{
System.out.println("猪吃饲料");
}
public void gongdi()
{
System.out.println("拱地");
}
}
public class DuoTaiDemo
{
public static void main(String[] args)
{
/*
Cat c=new Cat();
//c.eat();
//c.catchmouse();
//让另一只猫吃东西
Cat c1=new Cat();//重复使用,封装方法;
//c1.eat();
function(c);
function(c1);

Dog d=new Dog();
//d.eat();
d.kanjia();
function(d);
function(new Dog());

Pig p=new Pig();
function(p);

//转换:
Animals c2=new Cat(); //猫也是动物,具备动物类吃的属性(一个对象具备多种形态)
c2.eat();	//子类中也有吃的方法,调用子类中的eat方法;

Animals d1=new Dog(); //类型提升;
d1.eat();

function(new Cat());	//提高代码的扩展性;
function(new Dog());
function(new Pig());

//等学完反射,这块代码就可以不用动了;

//如果想要调用猫的特有方法该如何操作?
//强制将父类的引用转成子类类型;向下转型;
Cat c3=(Cat)c2; //小动物强转成猫咪;
c3.catchmouse();

//注意:千万不能将父类类型转成子类类型;
//我们能转换的是父类引用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换;
//多态自始至终都是子类对象在变化;
*/

function(new Cat());
function(new Dog());
function(new Pig());

//function(new Mouse());
}
//都具备吃的行为,因为它们都是动物;
/*
public static void  function(Cat c)
{
c.eat();
}
public static void  function(Dog d)
{
d.eat();
}
public static void  function(Pig p)
{
p.eat();
}
*/
public static void function(Animals a)
{
a.eat();
/*
if(a instanceof Animals)//判断的时候父类不要写在上面,因为条件满足后面的代码就都不会再判断了;
{}
else{}
*/
if(a instanceof Cat)
{
Cat c=(Cat)a;
c.catchmouse();//抓老鼠;
}
else if(a instanceof Dog)
{
Dog c=(Dog)a;
c.kanjia();//看家;
}
else if(a instanceof Pig)
{
Pig c=(Pig)a;
c.gongdi();//拱地;
}
else
{
System.out.println("Another Animals");
}
}
}
//一般不使用这种方法进行判断,因为当增加子类的时候,程序的扩展性极差;
//instanceof用来判断所属类型;
//instanceof在两种情况下使用:
//1.当子类个数很少的时候;
//2.当传的类型需要进行其他操作的时候(比如比较的时候),必须要确定它是哪种子类型(因为要调用特殊方法进行比较),这是用instanceof判断一下;

多态的特点:

1.多态中成员函数(非静态)的特点:

         在编译时期,参阅引用类型的变量所属的类中是否有调用的方法,如果有,编译通过,否则编译失败;

         在运行时期,参阅对象所属的类中是否有调用的方法。

         简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

 

 涉及到面试的内容,开发时一般不多见:

    在多态中成员变量的特点 :无论编译还是运行,都参考左边(引用变量所属的类)

2.在多态中,静态成员函数的特点:无论编译和运行,都参考左边; 静态参考的是类。
class Fu
{
int num=5;
void method1()
{
System.out.println("fu method1");
}
void method2()
{
System.out.println("fu method2");
}
static void method4()
{
System.out.println("fu method4");
}
}
class Zi extends Fu
{
int num=8;
void method1()
{
System.out.println("zi method1");
}
void method3()
{
System.out.println("fu method3");
}
static void method4()
{
System.out.println("zi method4");
}
}
public class DuoTaiTedian
{
public static void main(String[] args)
{
Zi z=new Zi();
z.method1();
z.method2();
z.method3();
System.out.println(z.num);//结果是8

Fu f=new Zi();
f.method1();
f.method2();//调用子类中的method2方法;
//f.method3();
System.out.println(f.num);//结果是5;

f.method4();//开发时一般不覆盖静态;静态方法是不需要对象的。
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息