黑马程序员--面向对象

   -------android培训、java培训、期待与您交流! ----------

1、什么叫面向对象?

面向对象(Object-Oriented,简称OO)就是一种常见的程序结构设计方法。
面向对象思想的基础是将相关的数据和方法放在一起,组合成一种新的复合数据类型,然后使用新创建的复合数据类型作为项目的基础。

面向对象是一个很抽象的概念,它相对面向过程而言。过程与对象都是一种解决问题的思想。

面向过程:强调的是功能行为,一种过程,先干啥,再干啥;

面向对象:将功能封装到对象里,强调的是具备某功能的对象;

按照面向对象的思想,可以把任何的东西看做对象!

 

面向对象的三个特征:

封装(Encapsulation);

继承(Inheritance);

多态(Polymorphism)

 

我的总结:

面向过程:强调的是具体的功能实现;(执行者)

面向对象:强调的是具备功能的对象。(管理者)


2、类的概念


是一组事物共有特征和功能的描述。

生活中描述事物无非就是描述事物的属性和行为。
如:人有身高,体重等属性,有说话,打球等行为。

Java中用类class来描述事物也是如此。


属性:对应类中的成员变量。
行为:对应类中的成员函数。


定义类其实在定义类中的成员(成员变量和成员函数)

成员:成员变量<-->属性,成员函数<-->行为。

属性对应是类中变量,行为对应的类中函数或方法。
其实定义类,就是在描述事物,就是在定义属性和方法,属性和行为共同成为类中的成员(成员变量和成员方法)。

Eg

class Person{
        //属性
	private String name;
	private int age;
	private int sal;
	//方法
	public void show(){
		System.out.println("个人情况:"+name+age+sal);
	}
}
成员变量和局部变量的区别:

成员变量:
成员变量定义在类中,在整个类中都可以被访问。
成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
成员变量有默认初始化值。

局部变量:
局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
局部变量没有默认初始化值。


构造函数:用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种。

特点

    1.该函数的名称和所在类的名称相同。

    2.不需要定义返回值类型。

    3.该函数没有具体的返回值。


注意:
1
、一般函数和构造函数什么区别呢?

构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化。
一般函数:对象创建后,需要函数功能时才调用。

构造函数:对象创建时,会调用并且只调用一次。
一般函数:对象创建后,可以被调用多次。

2、创建对象都必须要通过构造函数初始化。
一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。

3、多个构造函数是以重载的形式存在的。


匿名对象

匿名对象是对象的简化形式。
匿名对象两种使用情况:当对对象方法仅进行一次调用时;匿名对象可以作为实际参数进行传递。


封装(Encapsulation

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

好处:
将变化隔离。
②便于使用。
③提高重用性。
提高安全性。

封装原则:
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。


           private:关键字

A:用于修饰成员变量和成员方法。
B:被修饰的内容在其他类中是不可以被访问的。

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

this:关键字

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

           换言之:this代本类对象的引用。

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

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

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

this代表对象。代表哪个对象呢?当前对象。

this:就是所在函数所属对象的引用。

简单说:哪个对象调用了this所在的函数,this就代表哪个对象。


        static关键字

被修饰后的成员具备以下特点:
随着类的加载而加载。
优先于对象存在。
被所有对象所共享。
可以直接被类名调用。


成员变量和静态变量的区别?
1
、两个变量的生命周期不同
    
成员变量随着对象的创建而存在,随着对象被回收而释放。
    
静态变量随着类的加载而存在,随着类的消失而消失。
2
、调用方式不同
    
成员变量只能被对象调用。
    
静态变量可以被对象调用,还可以被类名调用。
3
、别名不同
    
成员变量也称为实例变量。
    
静态变量也称为类变量。
4
、数据存储位置不同
    
成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
    
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。


使用注意:
静态方法只能访问静态成员,如果访问非静态成员,就会报错!

原因:静态方法和变量存在的时候,对象还不存在,非静态变量也不存在,肯定无法访问。


静态方法中不可以写thissuper关键字。

原因:静态方法存在的时候,对象还不存在,this代表的就是调用方法的那个对象,既然不存在,肯定不可以写在静态方法中。


主函数是静态的

主函数特殊之处:
1
、格式是固定的。
2
、被jvm所识别和调用。

主函数各成分解析:

public:权限必须是最大的,被jvm调用。
static
:不需要对象调用,直接用主函数所属类名调用即可。
命令行窗口中输入:java StaticDemo,实际上就是在执行StaticDemo.main();。
void:主函数不需要具体的返回值。
main:函数名,不是关键字,只是一个jvm识别的固定的名字。
String[]args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。

super关键字

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

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

classTest{ 

static{ 

System.out.println("Static Code"); 

} 

{ 

System.out.println("Code"); 

} 

Test(){ 

System.out.println("Test Code"); 

} 

public static voidmain(String[] args){ 

System.out.println("Main Code"); 

new Test(); 

} 

} 

/* 

private封装 

this用法 

构造函数 

static小应用 

对象初始化顺序 

*/ 

class Person { 

private String name; 

private int age; 

private static String country ="cn"; 

{ 

System.out.println("cry..."); 

} 

public int getAge() { 

returnage; 

} 

public void setAge(intage) { 

this.age = age; 

} 

Person(){} 

Person(String name,int age) { 

this.name = name; 

this.age = age; 

} 

// 进行name显示初始化值,等同于设置name


public void setName(String name){ 

this.name = name; 

} 

public String getName() { 

return name; 

} 

public void speak() { 

System.out.println("name=" + name +"..age=" + age); 

show();// 打印当前对象的country,this也被省略 

} 

public static void show() { 

System.out.println("country=" + country); 

} 

} 

class PersonTest { 

public static void main(String[] args) { 

Person p = new Person("Xcc",19); 

p.setName("黑马程序员"); 

p.setAge(20); 

p.speak(); 

} 
} 
Person p = new Person("Xcc",19);
这句话都做了什么?
1.因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中
2.执行该类中的static代码块,如果有的话,给Person.class类进行初始化
3.在堆内存中开辟空间,分配内存地址
4.在堆内存中建立对象的特有属性,并进行默认初始化(name=null age=0 country=null)
5.对属性进行显示初始化(也就是属性初始化,如果没有赋值就是默认初始化的值 name=null age=0 country="cn")
6.对对象进行构造代码块初始化

7.对对象进行对应的构造函数初始化

8.将内存地址赋给栈内存中的p变量

继承 ( Inheritance )

在Java中使用extends 关键字来标识两个类的继承关系。其基本思想是基于某个父类的扩展,制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具有的属性和方法,或者直接重写父类中的某些方法。



多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
多个类可以称为子类,单独这个类称为父类或者超类。

注意:

子类可以直接访问父类中的非私有的属性和行为。

子类无法继承父类中私有的内容。
父类怎么来的?共性不断向上抽取而来的。

好处:

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

2.让类与类之间产生了关系,提供了另一个特征多态的前提。


单继承:一个类只能有一个父类

多继承:一个类可以有多个父类

Java只支持单继承,不支持多继承一个类只能有一个父类,不可以有多个父类。

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

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

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

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

子父类中变量的特点:

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

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

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

     子父类中函数的特点:


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

           当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,

           而是使用覆盖,保留父类的功能定义,并重写功能内容。


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

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

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

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

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

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

                  2)子类一定要访问父类中的构造函数,因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据

                       进行初始化的,所以子类在对象初始化时 ,要先访问一下父类中的构造函数,如果要访问父类中指定的构造函数,可以通过手动定义

                       super语句的方式来指定。

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

子类的实例化过程:

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

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

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

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

class Super{ 
Super(){ 
//Super的父类又是谁呢?查阅API发现是Object,所以类都有一个父类就是Object。 
super(){} 
}
int num = 5; 
public int show(){ 
return num; 
} 
} 
class Extends extends Super{ 
Extends(){ 
super(){} 
} 
public String name; 
Extends(String name){ 
this(){} 
//等于Extends(){},如果定义了this(){}那么super(){}语句就不在了。 
//而是在另外调用的构造函数里 
this.name=name; 
} 
public int num = 10; 
/* 
子类的特有方法 
*/ 
public int method(){ 
return super.num; 
} 
/*继承父类的方法 
public int show(){ 
return num; 
} 
*/ 
} 
class Test{ 
public static void main(String[] args){ 
//创建子类对象。 
Extends zi =  new Extends(); 
//调用子类的method方法,获取父类的num值。 
int methodnum = zi.method(); 
//为什么可以调用父类的show方法呢?因为子类继承了父类,所以就有了父类的方法。 
int shownum = zi.show(); 
//打印结果为5,父类的变量。 
System.out.println("methodnum="+methodnum); 
//打印结果为10,子类的变量,因为子类有着和父类同样的成员变量,所以进行了覆盖。 
System.out.println("shownum="+shownum); 
//创建父类对象。 
Super fu = new Super(); 
//这样调用是否可以?答案是不可以的,因为这是子类特有方法,父类无法访问。 
//fu.method(); 
} 
} 

final——关键字最终值

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

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

3、被 final修饰的方法。

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

5、当在描述事物时,一些数据的出现 值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便于阅读,

  而这个这不需要改变,所以加上final修饰。

6、比如 π值。

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

8、一般是public static final 。。。这么使用。

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

抽象类——关键字:abstract 只能修饰类和方法

抽象:笼统,模糊,看不懂!不具体。

抽象类的概述:

当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取。

这时,只抽取功能定义,而不抽取功能主体。

抽象类的特点(abstract)

1.方法只用声明没有实现时,该方法就是抽象方法,需要被abstract修饰。

 抽象方法必须定义在抽象类中。该类必须被abstract修饰。

2.抽象类不可以被实例化(也就是创建对象的意思),为什么?因为调用抽象方法没意义。

3.抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化。

  否则, 这个子类还是抽象类。

问题:

1.抽象类中有构造函数吗?

有,用于给子类进行初始化。

2.抽象类可不可以不定义抽象方法吗?

可以的。但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。 通常这个类中的方法有方法体,但是却没有内容。

3.abstract关键字不可以和那些关键字共存?

private不行,抽象方法需要实现,私有,没办法实现覆盖原有方法。

static不行,静态的不用对象,直接类名调用,抽象方法没内容,没意义。

final不行,水火不容,抽象要被覆盖,但是final不能覆盖。

4.抽象类和一般类的异同点。

相同点:抽象类和一般类都是用来描述事物的,都在内部定义了成员。

不同点:

1.一般类有足够的信息描述事物。 抽象类描述事物的信息有可能不足。

2.一般类中不能定义抽象方法,只能定义非抽象方法。 抽象类中可定义抽象方法,同时也可以定义非抽象方法。

3.一般类可以被实例化。 抽象类不可以被实例化。

5.抽象类一定是父类吗?

是的。因为需要子类覆盖其方法后才可以对子类实例化。

接口

当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口 interface

格式: interface接口名{} 定义接口使用的关键字不是class,是interface 对于接口当中常见的成员:而且这些成员都有固定的修饰符。

1,全局常量。public static final 

2,抽象方法。public abstract

由此得出结义,接口中的成员都是公共的权限,都是public

 类与类之间是继承关系,类与接口之间是实现关系。

实现: implements

注意:接口不可以实例化。只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。

否则这个子类也是抽象类。

在Java中不直接支持多继承,因为会出现调用的不确定性。

所以Java将多继承机制进行改良,在Java中变成了多实现。

一个类可以实现多个接口。

接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。

接口的出现避免了单继承的局限性。

类与类是继承关系,类与接口是实现关系,接口与接口之间是继承关系,而且接口可以多继承。

 注意:接口的出现再次打破了单继承的局限。

接口的特点:

1.接口是对外暴露的规则。

2.接口是程序的功能扩展。

3.接口的出现降低耦合性。

4.接口可以用来多实现。

5.类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

6.接口与接口之间可以有继承关系。

接口与抽象类的异同点:

相同点:都是不断向上抽取而来的。

不同点:

1.抽象类需要被继承,而且只能单继承。接口需要被实现,而且可以多实现。

2.抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。 接口中只能定义抽象方法,必须由子类去实现。

3.抽象类的继承,是is a关系,在定义该体系的基本共性内容。接口的实现是like a关系。



interface Inter_1{

public static final int PI = 3.14;

public abstract void show(); 

}

interface Inter_2{

/*如果该类是接口的话,默认是权限修饰符是 public static final */ int PI = 4; 

/*如果该类是接口的话,默认是权限修饰符是 public abstract */voidshow(); 

} 

interface Inter_3 extends Inter_1{ 

public abstract void show(); 

} 

class Demo implements Inter_1,Inter_2, Inter_3{ 

public static final int PI = 3.14; 

public void show(){ 

System.out.println("Demo implements Inter_1"); 

} 

} 

class Test{   

public static void main(String[] args){   

Demo d = new Demo(); 

d.show();//"Demo implements Inter_1" 

System.out.println(d.PI); 

//最简单的调用接口类的方法,因为接口类的常量默认是静态的,所以可以类名.调用)


System.out.println(Demo.PI); 

System.out.println(Inter_2.PI); 

System.out.println(Inter_3.PI);//打印Inter_1的常量


}   

} 

注意:接口的属性都是常量,而且是全局常量。接口中的方法都是抽象的。 

(很重要)日后开发就是这种模式,一个项目大家分一点,一个人实现一个功能,就是这样机制。 

接口的应用 

/* 

需求:数据库的操作。 

数据是:用户信息。 

1,连接数据库。JDBC  Hibernate 

2,操作数据库。 

c create r read  u update  d delete 

3,关闭数据库连接。 

*/ 

interface UserInfoDao{ 

public void add(User user); 

public void delete(User user); 

} 

class UserInfoByJDBC implementsUserInofDao{ 

public void add(User user){ 

1,JDBC连接数据库。; 

2,使用sql添加语句添加数据。; 

3,关闭连接。 

} 

public void delete(User user){ 

1,JDBC连接数据库。; 

2,使用sql添加语句删除数据。; 

3,关闭连接。 

} 

} 
class UserInfoByHibernate implements UserInfoDao{ 

public void add(User user){ 

1,Hibernate连接数据库。; 

2,使用sql添加语句添加数据。; 

3,关闭连接。 

} 

public void delete(User user){ 

1,Hibernate连接数据库。; 

2,使用sql添加语句删除数据。; 

3,关闭连接。 

} 

} 
class  DBOperate{ 

public static void main(String[] args) { 

//UserInfoByJDBC ui = new UserInfoByJDBC(); 

//UserInfoByHibernate ui = new UserInfoByHibernate(); 

//UserInfoDao ui = new UserInfoByHibernate(); 

UserInfoDao ui = new UserInfoByJDBC();


ui.add(user); 

ui.delete(user); 

} 

} 

多态 ( Polymorphism )

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

1.多态的体现

父类的引用指向了自己的子类对象。

父类的引用也可以接收自己的子类对象。

2.多态的前提

必须是类与类之间有关系。要么继承,要么实现。 通常还有一个前提:存在覆盖。

3.多态的好处

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

4.多态的弊端

提高了扩展性,但是只能使用父类的引用访问父类中的成员。


abstractclass Animal { 
        public abstractvoid eat(); 
} 
class Cat extends Animal  {   
        public void eat(){   
                System.out.println("吃鱼");   
        }   
        public void catchMouse()  {   
                System.out.println("抓老鼠");   
        }   
}   
class Dog extends Animal  {   
        public void eat()  {   
                System.out.println("吃骨头");   
        }   
        public void kanJia()  {   
                System.out.println("看家");   
        }   
}   
class Pig extends Animal  {   
        public void eat()  {   
                System.out.println("饲料");   
        }   
        public void gongDi()  {   
                System.out.println("拱地");   
        }   
}   
   
class DuoTaiTest   {   
        public static void main(String[] args)   {   
                Animal a = new Cat(); 
                //类型提升。 向上转型。 父类类型指向子类对象  
                a.eat();  //吃鱼 
   
                //如果想要调用猫的特有方法时,如何操作?   
                //强制将父类的引用。转成子类类型。向下转型。   
                Cat c = (Cat)a;   
                c.catchMouse(); //抓老鼠 
   
                //不要出现这样的操作,就是将父类对象转成子类类型。   
                //我们能转换的是父类应用指向了自己的子类对象时。 
                //该应用可以被提升,也可以被强制转换。   
                //多态自始至终都是子类对象在做着变化。   
                //      Animal a = new Animal();   
                //      Cat c = (Cat)a;   
                   
   
                /*  
                父 x = new 子();  
  
                x.工作();  
  
                子 y = (子)x;  
  
  
                y.玩();  
                */   
                function(new Cat()); 
                function(new Dog());   
                function(new Pig());   
   
   
            }   
            public static void function(Animal a){//Animal a = new Cat();   
                if(!(a instanceof Animal)) {  
                    System.out.println("类型不匹配");  
                }  
                else{ 
                        a.eat(); 
                        if(a instanceof Cat)  {   
                                Cat c = (Cat)a;   
                                c.catchMouse();   
                        } 
                        else if(a instanceof Dog)  {   
                                Dog c = (Dog)a; 
                                c.kanJia(); 
                        } 
                       else if (ainstanceof Pig()){ 
                                Pig p = (Pig)a; 
                                a.gongDi(); 
                        } 
                } 
                //instanceof : 用于判断对象的类型。  
               //对象 intanceof 类型(类类型 接口类型)    
           }   
}
注意:

成员的特点:

1.成员变量

编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有,编译失败。

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

简单总结:编译和运行都参考等号的左边。

2.成员函数(非静态)

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

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

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

3.静态函数

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

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

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

简单总结:编译和运行都看左边。

总结:非静态成员函数,编译时看左边,运行时看右边。其他都看左边。

 

























你可能感兴趣的:(JAVA)