------- android培训、java培训、期待与您交流! ----------
面向对象的三大特征:
1、封装 2、继承 3、多态
封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。
多态:Java引用有2个类型状态:一个是编译时的类型,一个是运行是的类型,编译时的类型由声明该变量使用的类型决定,运行时的类型由实际赋给该变量的对象决定,如果编译时的类型和运行时的类型不一致,就会出现所谓的多态。比如定义了Object a=new Person();这里声明的是一个object类型,但在运行的时候很可能是个person类型。多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
继承:在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
下面我们看看对象和类之间的关系
类就是对现实生活中事物的描述。对象就是这类事物中实实在在的存在的个体。比如我们把水果定义成一个类,那么苹果,香蕉都是属于这个水果类中具体的对象。具体的对象都是new出来的 都放在堆内存中
下面我们定义一个类。 我们定义一个水果类,那么他得有颜色、形状、味道、他还能吃。那么看看我们的定义,定义类其实就是描述属性和行为,分别称为成员属性和成员方法。
class Fruit{
String color="红色";//颜色
Stirng shape="圆形"; //形状
void eat(){//行为,可以吃
System.out.println(color+"好吃"+shape);
}
}
然后在生成一个对象看看
,生产一个水果,我们就是通过new关键字来生产,就是在堆内存中产生一个实体。
Fruit fruit = new Fruit();//我们通过上面的Fruit类产生的,那么我们这个fruit对象就有上面的属性和行为 这里的fruit是三种引用类型中的类类型变量。他指向了堆内存中的new Fruit()对象
大家看见我们上面的color和shape属性都是属于类的,并不是属于某个方法或者语句的,那么这里又引出了两个概念。
1、成员变量和局部变量,成员变量的作用域是整个类中,而局部变量的的作用域只是某个方法或者语句中。
2、成员变量的空间都在堆内存中,垃圾回收器会去回收,而局部变量都是定义在栈内存中,是自动回收。
——————————————————————————————————————————————————————————————————————
匿名对象
new Fruit().eat ;我们这里在堆内存中开辟了一块空间产生了一个对象,但我们发现并没有任何引用指向它,那么他就是一个匿名对象。
Fruit f = new Fruit();f.color="蓝色";
new Fruit().color="蓝色";
我们看见上面两句话,第一行是产生了一个对象并有一个f指向了他,第二行产生后没有引用指向他,那他就是个垃圾,就会被回收。这样看来貌似我们的匿名对象没有什么意义,但匿名对象一般有两种使用方式。如下
1、如果只对对象的某个行为方法只使用一次的话,使用匿名对象比较方便 如: new Fruit().eat();我们打印出来这个对象吃的方法,他是有具体意义的。
2、将匿名对象作为参数传给一个方法。如:public static void change(Fruit f){}我们定义一个方法他需呀传入一个Fruit对象做为参数,我们就可以用change(new Fruit()){}去完成。
——————————————————————————————————————————————————————————————————————————————————————
private:私有,权限修饰符:用于修饰类中的成员(成员变量和成员函数),用private修饰的只在本类有效。这也是封装的一种表现形式。
class Person{
private int age;//将age私有化,不能被外部直接访问,但我们可以给他提供一个外部方法
public void setAge(int a){//这里就提供一个供外部访问的方法
age = a;
}
public int getAge(){//这里就提供一个供外部访问的方法
return age;
}
void speak(){
System.out.println("hello");
}
}
——————————————————————————————————————————————————————————————————————————————————
构造函数:
特点:1、函数名与类名相同,不用定义返回类型。
2、如果没有定义构造函数,当建立新对象时,也会调用无参数的默认构造函数,而当在类中自定义了构造函数之后,默认的构造函数不再存在。
3、可以重载。
作用:给对象进行初始化。
class Person{
public Person(){//这个就是我们定义的无参的构造函数,用以初始化对象
System.out.println("perosn run");
}
public static void main(String[] args){
new Person();//这里建立一个对象,就调用与之对应的构造行数,从而打印出perosn run
}
}
构造函数与一般函数:
构造函数只在对象建立时自动运行一次,一般方法可以随时被对象调用多次;一个类内一般函数可以被构造函数调用,但一般函数不能调用构造函数
——————————————————————————————————————————————————————————————————————————————————————构造代码块 他也是用于对象初始化执行,但是他要优先去构造函数执行,而且他是对所有的对象都进行统一初始化。而构造函数是对对应的对象进行初始化
类中只有函数体没有函数名的代码块,作用是给所有对象进行统一初始化
class Person{
{//构造代码块
System.out.println("person cry>>>>>>>>>>>>>>>>>>");
}
public Person(){//这个就是我们定义的无参的构造函数,用以初始化对象
System.out.println("perosn run");
}
public static void main(String[] args){
new Person();//这里建立一个对象,就调用与之对应的构造行数,从而打印出perosn run
}
}
————————————————————————————————————————————————————————————————————————————————————————
this关键字 this代表它所在函数所属对象的引用。简单说:哪个对象调用this所在的函数,那么this就代表哪个对象。用于区分局部变量与成员变量同名
this的应用:当定义类中功能的时候,该函数内部要用到调用该函数的对象时,这个时候用this来标示这个对象。this语句必须放在第一行。如有相同构造方法相互调用的时候,可以用到this语句格式:this(name);
class Person{
private int age;//
public void setAge(int age){//初始化的时候,哪个对象在调用这个函数,那么这个this就代表哪个对象
this.age = age;
}
public int getAge(){//这里就提供一个供外部访问的方法
return age;
}
void speak(){
System.out.println("hello");
}
}
——————————————————————————————————————————————————————————————————————————————————————
Static关键字
static表示静态修饰,是一个修饰符,用于修饰成员变量(成员变量和成员方法)。当成员被static修饰后,就多了一种访问方式,除了可以用被对象调用,还能被类直接调用。格式如:类名.静态成员。
static的特点:
1、随着类的加载而加载,随着类的消失而消失,他是依赖类的,跟对象没关系,他的声明周期最长。
2、优先于对象的存在,静态成员是先存在,然后才有对象的存在。
3、被所有对象共享,因为static修饰的成员变量是依赖类的,那么每个根据这个类生产的对象都可以访问static修饰的成员
4、可以被类名直接调用.类名.成员
实例变量和静态变量(类变量)的区别,在这之前我们再看看局部变量和成员变量。
局部变量——存在方法体、语句中的变量我们成为局部变量,他在栈内存中。他没有默认的初始值,得我们手动赋初始值。他的作用域仅限于方法体中。
成员变量——成员变量存在类中。他在堆内存中,有默认的初始化默认值。他的作用域是整个类中。
实例变量——也属于成员变量,但是他是依赖于对象的。访问他要利用对象去访问。没有对象即没有该对象的实例变量。要对象的产生才会有对应的实例变量产生在堆内存中。
静态变量——他是依赖于类的,当类加载的时候就会在方法区内存中开辟空间保存静态变量,当没有对象的时候他也可以被类直接调用。他是所有对象的共享变量。
下面我们再来说说实例变量和成员变量的区别:
1、存放位置不同,类变量随着类的加载而存在于方法区中,实例变量存在随着对象的建立而存在于堆内存中。
2、生命周期不同,类变量生命周期最长,随这里类的消失而消失,实例变量的生命周期随着对象的消失而消失。
public class Person {
private static String name="zs";//我们这里把name定义成了静态的变量
private static void speak(){//我们这里把方法也定义成了静态的变量
System.out.println("name---->"+name);
}
public static void main(String[] args) {
System.out.println(Person.name);//可以看见这里并没有产生对象,但我们依然访问到了该变量,这就是静态变量是依赖类的并没有依赖对象
Person.speak();
}
}
什么时候使用静态:因为静态修饰的内容用成员变量和成员函数。所以
1、当对象中出现共享数据时(这里是数据是指数值,不是指属性),可以节约内存。
2、当函数中没有访问到非静态数据的时候(对象中特有的数据),那么该函数可以定义成静态的。
————————————————————————————————————————————————————————————————————————————————————————
主函数——main
public static void main(String[] agrs){}主函数是一个特殊的函数,是程序的入口,可以被JVM调用。
主函数的定义:
public:代表函数的访问权限是最大的,公开的。
static:代表函数是静态成员,是随着类的加载而加载。
void:表示主函数没有具体返回值。
main:不是关键字,但是是一个特殊的单词,可以被JVM虚拟机识别。
String[] args:是函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。args 是arguments 的缩写 ,args就是命令行的参数
主函数是固定的格式,JVM只识别它。JVM在调用主函数的时候是传入的new String[0];看见没有他的长度是0.主函数可以被重载 , 但能被JVM识别并作为入口的固定格式是:public static void main(String [] args){}
public class Demo{
public static void main(String[] args){
for(int i =0;i<args.length;i++){//这里我们遍历args这个数组,打印
System.out.println(args[i]);
}
}
}
那么我们在执行那个这个程序都的时候应该是这样的javac Demo.java ------>java Demo 参数1 参数2 参数之间用空格隔开的。
————————————————————————————————————————————————————————————————————————————————————————
静态代码块
特点:随着类的加载而加载,而且只执行一次,用于给类的初始化,跟对象没关系,要记住跟对象真的没关系
public class Demo{
static{
System.out.println("b");
}
public static void main(String[] agrs){
System.out.println("a");
new Demo();
System.out.println("c");
}
}
![](http://static.oschina.net/uploads/space/2013/0109/155500_okcF_158350.png)
根据结果我们可以看出来,b要比a先打印,可以把看出静态代码块是比主函数优先的,然后打印了a,然后再new Demo()的时候创建了一个对象,但我们发现虽然创建了对象但并没有打印出b,这说明static代码块只执行一次。
————————————————————————————————————————————————————————————————————————————————————————
对象的初始化过程
我们以Person p = new Person()这句话为例,来说明下对象的初始化过程。
1、因为new用到了person.class文件,所以虚拟机会先加载person.class文件到内中。
2、执行该类中的静态代码块(static),如果有的话,给Person.class类进行初始化。
3、在内存中开辟空间,分配内存地址。
4、在堆中建立对象的特有属性,并进行默认的初始化。
5、对属性进行显示的初始化。
6、对对象进行构造代码块初始化。
7、对对象进行对应的构造函数初始化。
8、将内存地址赋值给栈内存中的p变量。
继承的好处:
1、提高了代码的复用性。
2、继承让类与类之间产生了关系,有了这个关系,才有后面的多态的关系。
需要注意的地方:不要为了获取其他类的功能而去继承,必须是类与类之间确实存在某种所属关系才可以继承。
class Person{//定义一个父类,人
private String name;//有姓名属性
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void speak(){//有说话行为
System.out.println(name+"我会说话!!!");
}
}
public class Teacher extends Person{//定义一个子类老师继承人这个父类
private String titles;//有自己的特性职称
public void settitles(String titles){
this.titles=titles;
}
public String gettitles(){
return titles;
}
public void teaching(){//有自己的行为,教书
System.out.println(getName()+"我会教书"+titles);
}
public static void main(String[] agrs){
Teacher teacher = new Teacher();
teacher.setName("张三");//这里我们看到虽然没有name属性,但他继承了Person。所以他也就有了这个属性
teacher.settitles("高级教师");
teacher.speak();//跟上面的属性一样,因为他继承了person这个父类
teacher.teaching();
}
}
![](http://static.oschina.net/uploads/space/2013/0109/221141_hyAE_158350.png)
Java中不支持多继承,因为多继承会带来安全隐患,当多个父类中定义相同的功能的时候,子类对象不知道要执行哪一个。但是Java中用多实现来弥补了这种机制。如下面的伪代码
下面的是伪代码
class Demo1{
void speak();
}
class Demo2{
void speak();
}
class Demo3 extends Demo1,Demo2{//这里假设可以多继承
Demo3 demo3 = new Demo3();
demo3.speak();//那么我们这里调用的到底是谁的方法就成疑问了,所以Java不支持多继承。
}
如何使用继承体系中的一个功能:
1、先查阅体系中父类的描述,因为父类中定义的是该体系中的共性的功能。通过了解共性,就能了解体系的基本功能。
2、在具体调用的时候,要创建最子类的对象,因为有的父类可能创建不了(抽象类),子类拥有更丰富的属性和方法。