-------android培训、java培训、期待与您交流! ----------
面向对象(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、数据存储位置不同
成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
使用注意:
①静态方法只能访问静态成员,如果访问非静态成员,就会报错!
原因:静态方法和变量存在的时候,对象还不存在,非静态变量也不存在,肯定无法访问。
②静态方法中不可以写this,super关键字。
原因:静态方法存在的时候,对象还不存在,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.静态函数
编译时:参考引用型变量所属的类中的是否有调用的静态方法。
运行时:参考引用型变量所属的类中的是否有调用的静态方法。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
简单总结:编译和运行都看左边。
总结:非静态成员函数,编译时看左边,运行时看右边。其他都看左边。