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

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

 

 

面向对象(java核心)

 

对象:

1.基本概念:

 *面向对象是相对面向过程而言

 *面向对象和面向过程都是一种思想

 *面向过程强调的是功能行为

 *面向对象将功能封装进对象,强调具备了功能的对象

 *面向对象是基于面向过程的

 

2.特征:1,封装    2 继承    3,多态

(万物皆对象)

 以后开发过程,其实就是找对象使用,没有对象就创建一个对象。

 找对象-建立对象-使用对象-维护对象的关系。

 

3.类和对象的关系:

  类:对现实生活中事物的描述。

  对象:就是这类事物实实在在存在的个体。

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

 (映射到java中,描述就是class定义的类。)

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

 

 

4.成员变量和局部变量:(作用范围不同)

  *成员变量作用于整个类中。

  *局部变量作用于函数中,或者语句中。

  在内存中的位置:

  *成员变量在堆内存中,因为对象的存在,才在内存中存在。

  *局部变量,存在栈内存中。

5.区别:

 *成员变量随着对象的创建而存在,随着对象的消失而消失。 

 *局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。  

 *成员变量都有默认初始化值。 

 *局部变量没有默认初始化值。 

 

6.匿名对象使用方式:

1)当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。

2)可以将匿名对象作为实际参数进行传递。

匿名对象

new People().name="张三";相当于:People p=new Peolple();p.name=”张三”;

 

 

匿名对象,有名对象区别

匿名对象创建完执行下一条语句前就销毁了,即是无意义的调用属性,用在只调用对象的方法,一次时,比较简化(调用属性一般是没意义的),有名对象进行多个成员(属性,行为)调用

匿名对象可作为实际参数进行传递

 

 

 

 

封装(Encapsulation):是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。 

 

1.封装好处: 

1)将变化隔离; 

2)便于使用。 

3)提高重用性。 

4)提高安全性。 

 

2.封装原则: 

*将不需要对外提供的内容都隐藏起来。 

*把属性都隐藏,提供公共方法对其访问。 

 

3.private:关键字

A:用于修饰成员变量和成员方法。

B:被修饰的内容在其他类中是不可以被访问的。 

注意:私有仅仅是封装的一种体现而已。

 

 

构造函数: 

A.构造函数特点: 

  1)函数名与类名相同。

  2)不用定义返回值类型。 

  3)不可以写return语句。

 

B.构造函数:构建创造对象时调用的函数。 
C.构造函数作用:给对象进行初始化。

                创建对象都必须要通过构造函数初始化。 

 

*一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。 

*如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。 

 

 

注意: 

1.默认构造函数的特点。 

2.多个构造函数是以重载的形式在在的。 

 

 

 

D.一般函数和构造函数什么区别呢? 

*构造函数:对象创建时,就会调用与之对应的构造函数,给对象进行默认初始化。 

*一般函数:对象创建后,需要函数功能时才调用。(函数只有被调用才执行) 

 

*构造函数:对象创建时,只调用一次。 

*一般函数:对象创建后,可以被调用多次。 

 

E.什么时候定义构造函数呢? 

*在描述事物时,该事物已存在就具备一些内容,这些内容都定义在构造函数中。 

*构造函数可以有多个,用于对不同的对象进行针对性的初始化。 

多个构造函数在类中是以重载的形式来体现的。 

 

F.构造代码块 

  1.构造函数块作用:给所有对象进行初始化。  

  2.对象一建立就运行,而且优先于构造函数执行和构造函数的区别: 

    构造代码块是给所有对象进行统一初始化; 而构造函数是给对应的对象进行初始化。 

  3.构造代码块中定义的是不同对象共性的初始化内容。 

 

总结:构造代码块和构造函数共性的地方就是当对象创建时,就给对象进行初始化一次。

注意:构造代码块,提高效率,由{}括起来的代码

构造代码块的作:让变量在内存中尽可能快的消失,提高效率,把所有构造方法中的共同      定义在构造代码块中,提高代码的复用性,优先于构造方法执行。

*局部代码块定义在方法中

 

 

 

关键字(this  super   static)

A.this:关键字 

  1)特点:this代表其所在函数所属对象的引用。 

          this代本类对象的引用。 

 

  2)什么时候使用this关键字呢? 

    *当在函数内需要用到调用该函数的对象时,就用this。 

    *当成员变量和局部变量重名,可以用关键字this来区分。 

 

   总结:哪个对象调用了this所在的函数,this就代表哪个对象。

 

   注意:

 1.this也可以用于在构造函数中调用其他构造函数。 

 2.this只能定义在构造函数的第一行。因为初始化动作要先执行。 

 3.构造函数间调用只能用this。

代码示例:

class Person
{
private String name;
private int age;
Person(int age)//局部变量时age,成员变量也是age
{
this.age = age;//这里用this表示调用构造方法的对象
}
Person(String name)
{
this.name = name;
}
Person(String name,int age)
{
this(name);//this.name = name;
this.age = age;
}
 
public void speak()
{
System.out.println("name="+name+"...age="+age);
show();
}
public void show()
{
System.out.println(this.name);
}
}
 
class Test
{
public static void main(String args[])
{
Person p1 = new Person(20);
Person p2 = new Person("张三");
Person p13 = new Person("李四",21);
 
}
}


 

B.super关键字 

 

如果要在函数内访问类中的同名成员变量,用super进行区分。 

 

注意:每个类身上都是一个隐式的super();那么这个空参数的super构造函数是哪个呢?查阅API发现是Object,他是所有类的父类。 

 

 

C.static关键字

           用于修饰成员(成员变量和成员函数) 

1.被修饰后的成员具备以下特点: 

  1)随着类的加载而加载 

  2)优先于对象存在 

  3)被所有对象所共享 

  4)可以直接被类名调用 

 

 

2.static特点:

  1)static是一个修饰符,用于修饰成员。(成员函数,成员变量) 

  2)static修饰的成员被所有的对象所共享。 

  3)static优先于对象存在,因为static的成员随着类的加载就已经存在了。 

  4)static修饰的成员多了一种调用方式,可以直接被类名调用。类名.静态成员。 

  5)static修饰的数据是共享数据,对象中存储的是特有数据。 

 

 

3.成员变量和静态变量的区别?

  1)两个变量的生命周期不同。 

    *成员变量随着对象的创建而存在,随着对象的被回收而释放。 

    *静态变量随着类的加载而存在,随着类的消失而消失。 

  2)调用方式不同。 

    *成员变量只能被对象调用。  

    *静态变量可以被对象调用,还可以被类名.调用。 

  3)别名不同。 

    *成员变量也称为实例变量。 

    *静态变量称为类变量。 

  4)数据存储位置不同。 

    *成员变量存储在堆内存的对象中,所以也叫对象的特有数据。 

    *静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。 

 

 

4.什么时候该用static呢?

             如果某个内容是所有对象共享的,就用静态修饰。 

 

5.什么时候使用静态成员和函数呢?

            要从两方面下手:因为静态修饰的内容有成员变量和函数

 

6.什么时候定义静态变量(类变量)呢? 

           当对象中出现可共享的数据时,该数据被静态修饰。 

           对象中的特有数据要定义成非静态存在于堆内存中。 

 

7.什么时候定义静态函数呢? 

          当功能内部没有访问到非静态数据,或者对象的特有数据, 那么该功能可以定义成静态的 

 

 

注意:

1.静态方法可能访问静态成员类名.静态成员。 

2.静态方法中不可以写this,super关键字,因为静态先于对象操作 

 

静态有利有弊:

利处: 对对象共享的数据进行单独空间的存储,没有必要每个对象都存一份 ,可以被直    接被类名调用。 

弊端:生命周期过长,访问出现局限性(静态虽好,只能访问静态)

3.主函数是静态的 

  public static void main(String[] args) 

 

主函数特殊之处: 

1)格式是固定的。(除了args这个数组名字可以变,其他不行) 

2)被Jvm所识别和调用。 

 

  public:因为权限必须是最大的。 

  static:不需要对象的,直接用主函数所属类名调用即可。 

  void:主函数没有具体的返回值。(因为返一个值给虚拟机,虚拟机也害怕啊!是不是虚拟机没有内存存放) 

  main:函数名,不是关键字,只是一个Jvm识别的固定的名字。 

  String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。

 

8.什么时候定义静态函数? 

   当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。(说了也不清楚,下面来一个静态的应用) 

 

9.静态代码块: 

  格式: 

static{ 

静态代码块中的执行语句 

 

       } 

特点:随着类的加载而执行,只执行一次,并优先于主函数 

 

 

10.对象初始化的顺序: 

 

   静态代码块——>静态主函数——>构造代码块——>构造函数

11.静态的应用-工具类

->>

当一个类中创建了另一个类的对象,编译的时候会同时编译两个类文件;

 

/*

每一个应用程序中都有共性的功能,

可以将这些功能进行抽取,独立封装,以便复用。

 

虽然 可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。

 

发现问题:

对象是用于封装数据的,可是ArrayTool对象并未封装特有(非公性)数据。

操作数组的每一个方法度没有用到ArrayTool对象中的特有数据。

考虑让程序更严谨,不需要对象。

 

直接将这些方法定义成静态的,直接通过类名调用即可。

 

方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的,

为了更为严谨,强制让该类不能建立对象,

可以通过将默认的构造函数私有化完成。

 

空参数的构造函数不一定是默认构造函数,默认的是看不见的,写了就不是默认的了。

class Demo

{

   Demo(){}:当你定义了空参数的构造函数,就不是默认的了,而是自定义构造函数了。

}

 

1*/class ArrayTool//工具类,通常是静态的方法

{

private ArrayTool(){};//将默认的构造函数私有化,对方不能建立对象。

//获得最大值

public static int getMax(int[] arr)

{

int max=0;

for(int x=1; x<arr[max];x++)

{

if(arr[x]>arr[max])

max=x;

}

return arr[max];

}

    //获得最小值

public static int getMin(int[] arr)

{

int min=0;

for(int x=1; x<arr[min],x++)

{

if(arr[x]<arr[min])

min=x;

}

return arr[min];

     }

//选择排序

public static void selectSort(int[] arr)

{

for (int x=0;x<arr.length-1 ;x++ )

{

for (int y=x+1;y<arr.length ;y++ )

{

if (arr[x]>arr[y])

{

swap[arr,x,y];

 }

 }

  }

}

    //冒泡排序

public static void bubbleSort(int[] arr)

{

for (int x=0;x<arr.length-1 ;x++ )

{

for (int y=0;y<arr.length-x-1 ; y++)

{

if(arr[y]>arr[y+1])

{

swap(arr,y,y+1);

}

}

}

}

//互换数值,没必要提供出去,私有化

private static void swap(int[] arr,int a,int b)

{

int temp=arr[a];

arr[a]=arr[b];

arr[b]=temp;

}

//打印数组

public static void printArray(int[] arr)

{

System.out.print("[");

for (int x=0;x<arr.length ;x++ )

{

if(x!=arr.length-1)

System.out.print(arr[x]+",  ");

else

System.out.print(arr[x]+"]");

}

}

}

2class  ArrayToolDemo //调用工具类的方法

{

public static void main(String[] args) 

{

int[] arr={3,6,89,43,56};

int max=ArrayTool.getMax(arr);

System.out.println("Max="+max);

//能够创建对象,因为工具类有个默认的空构造函数。只要有属性或行为,就可以创建对象。

/*ArrayTool tool=new ArrayTool();//此对象没必要生成,将工具类的方法改为静态

int max=tool.getMax(arr);

System.out.println("Max="+max);

 

tool.printArray(arr);

tool.selectSort(arr);

tool.printArray(arr);

*/

}

}

 

 

 

继承:

 

概述:Java语言中,Java只支持单继承,不支持多继承。 

  一个类只能有一个子类(extends) 一个父类(super),不允许多个,容易有安全隐患。 

 

多继承隐患:

(1)比如,同时继承两个类,但是两个类中有连个同名函数。 

(2)但是Java保留了这种机制,并用另一种体现形式来完成表示,叫做多实现。 

(3)Java支持多层继承,也就是一个继承体系,B继承A,C继承B,这样C就既有了A的功能,又有了B的功能,这就是多继承。 

 

使用一个继承体系的功能 

(1)要想使用体系,先查阅体系父类的描述,因为父类中,定义的是该体系中共性的功能。 

(2)通过了解共性功能,就可以知道该体系的基本功能。 

(3)那么这个体系已经可以基本使用了。 

 

在具体调用时,要创建最子类的对象,还是父类对象? 

(1)有可能父类不能创建对象。 

(2)创建子类对象可以使用更多功能,包括基本的也包括子类特有的。 

 

总结:简单一句话,查阅父类功能,创建子类对象使用功能。 

 

继承的出现(Extends): 

1)提高了代码的复用性。 

2)让类与类之间产生了关系。有了这个关系,才有了多态的特性。 

 

注意: 

*千万不要为了获取其他类的功能,简化代码而继承。 

*必须是类与类之间有所属关系才可以继承,所属关系,父类、子类(is a)。 

 

 

 

聚集关系: 

      类与类之间不只有继承关系,也有聚集(包括聚合和组合)关系。 

聚合:球队由球员组成,球员是球队中的一个,球队中有球员。 

组合:比聚合更紧密,心脏和身体的关系,不可分割。 

 

 

 

 

子父类中变量的特点: 

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

2)子类要访问父类中的同名变量,用super。 

3)super的使用和this的使用几乎一致,this代表的本类对象的引用,super代表的是父类对象的引用。 

 

 

子父类中函数的特点(重写=覆盖): 

1)当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样,这种情况是函数的另一个特性:重写(覆盖)。 

2)当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖,保留父类的功能定义,并重写功能内容。 

 

覆盖:子类覆盖父类,必须保证子类权限大于等于父类,才可以覆盖,否则编译失败。静态只能覆盖静态。 

 

注意:重载只看同名函数的参数列表;重写 子父类方法要一模一样。 

 

 

子父类中构造函数的特点: 

1)在对子类对象进行初始化时,父类的构造函数也会运行。 

那是因为子类的构造函数默认第一行有一条隐式的语句super(); 

 

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

 

 

2)子类一定要访问父类中的构造函数,因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时 ,要先访问一下父类中的构造函数,如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。 

 

注意:super语句一定要定义在子类构造函数的第一行。 

继承弊端:打破了封装性。 

 

 

子类的实例化过程: 

结论: 子类的所有的构造函数,默认都会访问父类中空参数的构造函数。 

       因为子类每一个构造函数内的第一行都有一句隐式super(); 

       当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定 要访问父类中的构造函数;

       当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

 

 

代码块(面试题,理解)

(1)执行顺序:

静态代码块 --> 构造代码块 --> 构造方法

(2)注意事项:

静态代码块只执行一次

 

 

 

 

final关键字(最终值) 

*可以修饰类、函数、变量。 

*被 final 修饰的类,不可以被继承,为了并避免被继承,被子类复写功能。 

*被 final修饰的方法。 

*被final修饰的变量是一个常量,只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。 

*当在描述事物时,一些数据的出现 值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便于阅读, (而这个这不需要改变,所以加上final修饰。 )

比如 鹬怠? 

*作为常量,敞亮的书写规范所有字母都大写,如果由多个单词组成,单词间通过 _ 连接。 

*一般是public static final 。。。这么使用。 

*内部类定义在类中的局部位置上时,只能访问该局部被 final修饰的局部变量。

 

多态:

概述:对象在不同时刻表现出来的不同状态 。

 

多态的前提:

类与类之间必须存在关系(要么继承extends,要么实现implements

存在覆盖(重写)

父类引用指向子类对象

代码示例:

/*

基础班学生:

学习,睡觉。

高级班学生:

学习,睡觉。

 

可以将这两类事物进行抽取。

 

之前是指挥每一个对象去做事,现在是指挥一批对象去做事(指挥一批不同的动物吃饭);

*/

 

abstract class Student

{

public abstract void study();

public void sleep()

{

System.out.println("躺着睡");

}

}

 

class DoStudent//工具类

{

public void doSome(Student stu)

{

stu.study();

stu.sleep();

}

}

 

class BaseStudent extends Student

{

public void study()

{

System.out.println("base study");

}

public void sleep()

{

 System.out.println("坐着睡");

}

}

 

class AdvStudent extends Student

{

public void study()

{

System.out.println(" adv study");

}

}

 

class  DuoTaiDemo3

{

public static void main(String[] args) 

{

 

DoStudent ds = new DoStudent();

ds.doSome(new BaseStudent());

ds.doSome(new AdvStudent());

//BaseStudent bs = new BaseStudent();

//bs.study();

//bs.sleep();

//AdvStudent as = new AdvStudent();

//as.study();

//as.sleep();

}

 

}

 

 

 

多态在父类中的成员特点:
成员变量:

编译:参考引用类型变量所属的类中是否有调用的成员变量,有—>编译通过,反之则失败。

运行时:参考引用类型变量所属的类中是否有调用的成员变量,并运行所属类中的成员变量。

总结:编译运行都参考等号左边。

 

成员函数(非静态)

编译:参引用型变量所属的类中的是否有调用的函数。有—>编译通过,没有,编译失败。 

运行:参考的是对象所属的类中是否有调用的函数。 

总结:编译看左边,运行看右边。因为成员函数存在覆盖特性。  

静态函数:

        编译:参考引用型变量所属的类中的是否有调用的静态方法。 

    运行:参考引用型变量所属的类中的是否有调用的静态方法。 

注意(其实对于静态方法,是不需要对象的。直接用类名调用即可。) 

 

多态的弊端:父类引用不能使用子类特有功能。

 

多态弊端的解决方案:Fu  f  =  new  Zi(); //向上转型

Zi  z  =  (Zi)  f; //向下转型

Zi  z  =  new  Zi();

 

多态的好处:可以提高代码的扩展性和可维护性。

 

代码示例:

class Fu
{
static int num = 5;
int num2 = 6;
void method1()
{
System.out.println("fu method_1");
}
void method2()
{
System.out.println("fu method_2");
}
static void method4()
{
System.out.println("static fu method_4");
}
}
 
 
class Zi extends Fu
{
static int num = 8;
int num2 = 9;
void method1()
{
System.out.println("zi method_1");
}
void method3()
{
System.out.println("zi method_3");
}
 
static void method4()
{
System.out.println("static zi method_4");
}
}
class  Test
{
public static void main(String[] args) 
{
Fu f = new Zi();
 
System.out.println(f.num);//编译运行看左边
 
Zi z = new Zi();
System.out.println(z.num);
 
f.method1();//编译看左边,运行看右边
f.method2();//编译看左边,运行看右边
//f.method3();//编译运行看左边,编译失败
f.method4();//编译运行看左边
 
/*Fu f = new Zi();
System.out.println(f.num);//编译运行看左边
f.method4();//编译运行看左边
 
Zi z = new Zi();
z.method4();*/
 
/*Zi z = new Zi();
z.method1();//覆盖父类
z.method2();//继承父类
z.method3();//覆盖父类
*/	}
}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值