---------------------- android培训、java培训、期待与您交流! ----------------------
(一) 概述
面对对象概念:
面向对象是相对面向过程而言,面向对象和面向过程都是一种思想,面向过程强调的是功能行为,面向对象是将功能封装进对象,强调具备了功能的对象。面向对象是基于面向过程的。
面对对象特点:
将复杂的事情简单化 ,将程序员从执行者转换成了指挥者.
完成需求时
1.先要去找具有所需的功能的对象来用。
2.如果该对象不存在,那么创建一个具有所需功能的对象。
3.这样简化开发并提高复用。
(二) 举例
比如某天接到个项目要开发,我雇了几个人帮我开发,我就成了指挥者,被雇的人就成了对象.又比如餐厅点菜,服务员是对象.
面对对象的开发特点:
开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情.以后开发首先考虑的就是对象,没有对象就创建对象.
设计的过程:其实就是在管理和维护对象之间的关系。
(三) 类与对象的关系
面向对象的三个特征:
封装,继承,多态.
类是对现实事物抽象的描述,对象是事物的具体个体.描述事物就是在描述事物的属性和行为.
举例:
1.
//需求:描述汽车(颜色,轮胎数).
//属性对应类中的变量,行为类中的函数(方法).定义类其实就是在定义类中属性和行为,属性和行为称为类中的成员,即成员变量和成员函数.
class Car
{
//描述颜色
string color="红色";
//描述轮胎数
int num =4;
//运行行为
void run()
{
System.out.println(color+".."+mun);
}
}
2.
class CarDemo
{
public ststic void main(String[] args)
{
//生产汽车,在java中通过new操作符来完成.
//其实就是在堆内存中产生一个实体,这个实体就是一个对象.
Car c=new Car () ; //c是一个类类型变量,这个类型指向它所产生的实体.
//需求:将已有的车颜色改为蓝色,需要指挥该对象做事情,在java中的指挥方式是:对象. 对象成员
c.color="blue";//改变c这辆车的颜色.
c.run();//运行c这辆车.
Car c1=new Car();//再新建一辆车,还是红色,四个轮胎数.
c1.run();//运行c1这辆车.
}
}
注意:堆内存中的变量都有一个默认初始化值,字符串类型的默认初始化值是null,数值类型是0.
3.对象在内存中的情况举例:
Car c=new Car();//在栈内存中创建一个c,堆内存中创建一个Car实体,c指向这个Car.这叫多个引用指向同一个对象.
c.num=5;//堆内存中的num属性改为5.
Car c1=c;//栈内存中再创建一个c1,把c指向的地址值赋给c1.也就是说c和c1共同指向同一个堆内存中实体.
c1.color="green";//所以改动c1,也就改动了c.
c.run();//结果是绿色,5个轮胎数.
总结:对象中封装了属性和行为,想要操作对象,要明确操作那个对象和对象的哪个属性.
(四)成员变量和局部变量
定义类的时候没有写主函数,主函数是用来确保函数独立运行,如果类只是用来描述,则不需要写主函数.
成员变量:
1.定义在类中,作用于整个类中.
2.随着对象的建立而建立,存在于对象所在的堆内存中。
3.有默认初始化值。
局部变量:
1.只定义在局部范围内,作用于函数中或语句中,如:以前定义在函数中的变量.
2.存在于栈内存中。
3.作用的范围结束,变量空间会自动释放。
4.没有默认初始化值。只有定义了初始化值才能参与运算.
小结:什么时候需要定义成员变量呢?当类里面有多个函数需要共用同一变量的时候,就把这个变量定义为成员变量.
(五)匿名对象的应用
举例:
class Demo
public ststic void main(String[] args)
{
Car c=new Car();
c.num=5;
}
}
在修改对象属性值的时候可以省略对象名,写成:
class CarDemo
{
public ststic void main(String[] args)
{
new Car().num=5;//在堆内存中产生一个新对象,把num属性改为5,注意用匿名对象的时候栈内存中是不会产生东西的.new Car().color="blue";//在堆内存再产生一个新对象,把color改为blue,注意是重新产生的对象.
new Car().run();//再产生一个新对象,运行,结果是red和4,因为是新产生的对象,属性值没变.
}
}
注意匿名对象调用方法才有意义,调用属性没有意义.所以前面两句改变属性的命令是垃圾.
匿名对象的使用方式:
1.当对象的方法只调用一次的时候,可以用匿名对象,简化形式.但如果要对多个成员调用,就必须给对象起个名字.
2.可以将对象作为实际参数进行传递.
举例:
//需求:汽车修配厂,对汽车进行改装,将来的车改成黑色,三轮.
class Car
{
string color="红色";
int num =4;
void run()
{
System.out.println(color+".."+mun);
}
}
main()
{
Car c=new Car();//在堆内存中新建一个对象,在栈内存中命名为c指向这个对象.
show(c);//这里的c是上面命名的那个c,把c赋给了函数show.所以num变为3color变为blcak.
}
public static void show(Car c)//在栈内存中定义一个show的函数.{
c.num=3;
c.color="black";
c.run();
}
如果用匿名对象,上面的main函数可以写成:
main
{
show(new Car());//在堆内存中新建了一个对象,其属性的初始化值是red和4,然后在栈内存中定义了一个show函数,并把show函数中的c指向new Car().
}
(六)封装的概述
封装:Encapsulation,隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装的好处:
1.将变化隔离。
2.便于使用。
3.提高重用性。
4.提高安全性。
封装原则:
1.将不需要对外提供的内容都隐藏起来。
2.把属性都隐藏,提供公共方法对其访问。
(七)封装Private
class Person
{
private int age;//private私有,权限修饰符,用于修饰类中的成员(成员变量,成员函数).私有只在本类中有效.
public void setAge(int a)//在实际开发中属性可能会私有化,这时对于这些属性,所采用的方法无非就是设置和获取,也就是set和get.
{
if(a>0&&a<130)
{
age=a;
speak();
}
else
System.out.println("non");
}
public int getAge()
{
return age;
}
void speak()
{
System.out.println("age="+age);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p=new Person();
p.setAge=(20);
p.speak();
}
}
注意:封装不等于私有,私有仅仅是封装的一种表现形式.之所以停供访问方式,因为可以在方式中加入逻辑,判断等语句对被访问数据进行操作,提高代码健壮性.隐藏的最低权限是Private.set的返回值类型一般都是void,因为只是设置,不需要返回值.get一般没有参数,只是获取.
(八)构造函数
特点:
1. 函数名与类名相同
2. 不用定义返回值类型
3. 不可以写return 语句
举例:
class Person
{
Person()//这个就是构造函数,函数名和类名相同,没有返回值类型.
{
System.out.println("person run");
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p=new Person();//对象只要建立,就可以调用与之对应的构造函数,不需要再写p.Person();
new Person();//匿名对象
}
}
作用:
用于给指定对象进行初始化.比如某些一出现就具备某些行为的事物.
注意:
当类中没有定义构造函数时,那么系统会默认给该类加一个不含参数的构造函数.Person(){},因为构造函数是对象的基本,没有构造函数就没有对象,但当自定义了构造函数之后,默认的就消失了.
小细节:构造函数可以重载
例如:
class Person
{
private String name;//String就是字符串类型.
private int age;
Person()//初始化三个不同类型的人,有的有名字和年龄,有的没有.
{
System.out.println("A:name="+name+",age="+age);
}
Person(String n)//构造函数支持重载,函数名相同,参数不同.
{
name=n;
System.out.println("B:name="+name+",age="+age);
}
Person(String n,int a)
{
name=n;
age=a;
System.out.println("C:name="+name+",age="+age);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person();
Person p2=new Person("lisi");
Person p3=new Person("wangwu",10);
}
}
注意:考察对系统有默认的初始化构造函数理解,比如:
假如把上面的
Person()
{
System.out.println("A:name="+name+",age="+age);
}
注释掉,
再问下面主函数的结果,会报错说找不到初始化值,因为注释掉以后,类中还有其他已经定义了的构造函数,系统就不会自己创建默认的初始化构造函数,所以Person p1=new Person()这个对象就没有对应的构造函数,也就是没有对应的初始化值.
小细节:构造函数是可以被私有化的,私有化可以修饰成员变量和成员函数,构造函数也是成员函数,但是当构造函数被私有之后,外部的程序,比如在其他类里面创建对象进行调用的时候,这个被私有化的构造函数就不能创建对应的对象.
例如:
class Person
{
private Person(String x){}
}
class PersonDemo
{
public static void main(String[] args)
{
Person name=new Person("张三");
}
}
报错的原因是Person(String x)已经私有化了,下面的name对象不能访问这个被私有化的构造函数.
构造函数和一般函数的区别:
1.和一般函数写法不同
2.构造函数在对象一建立就运行,是给对象初始化.
3.一般方法是对象调用才执行,是给对象添加对象具备的功能.
4.一个对象建立,构造函数只运行一次.而一般方法可以被该对象调用多次.
set和get(设置和获取)的举例:
class Person
{
private String name;//定义成员变量name的原因是下面多个构造函数都会用到,私有化因为不会被对象直接调用.
private int age;
Person()
{
System.out.println("A:name="+name+","+"age="+age);//输出某个对象的name和age值.
cry();
}
Person(String n)
{
name=n;//对象建立之后,对象中的值传给n,n赋值给name.
System.out.println("B:name="+name+","+"age="+age);
cry();
}
Person(String n,int a)
{
name=n;
age=a;
System.out.println("C:name="+name+","+"age="+age);
cry();
}
public String getName()//获取某个对象的name值.
{
return name;
}
public int getAge()//获取对象的age值
{
return age;
}
public void setNameAge(String n,int a)//没有具体的返回值,没有return,所以返回值类型是void.
{
name=n;//更改某个对象的name值,而不用对象直接访问name这个成员变量,为了name的安全性,上面的输出name同理.
age=a;
}
public void cry()
{
System.out.println("cry...");
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person();
p1.cry();//这就是一般函数的好处,在初始化中只哭了一次,如果还想哭,则可以再继续调用一般函数,可以多次调用.
Person p2=new Person("张三");
Person p3=new Person("李四",20);
p1.setNameAge("王五",10);//把p1改名为王五,年龄改为10
System.out.println("A:name="+p1.getName()+","+"age="+p1.getAge());//打印验证p1的name和age是否改过来了
}
}
注意:对于构造函数在对象建立的时候只运行一次的理解:
Person p1=new Person();如果我还想让Person()这个构造函数再运行一次,不能在下面直接加Person p1=new Person(),这样是又创建了一个名为p1的对象,而应该把这个构造函数里面的参数在单独写一个一般函数,比如上面的cry(),这样,对象就可以多次调用了.构造函数是给对象一开始就赋予某些特性,而一般函数是对象的其他特性,方便对象多次调用.
小结:什么时候定义构造函数:
当分析事物时,该事物存在具备一些特性或者行为,那么将这些特性定义在构造函数中.如果事物有一开始就具有特殊的属性,比如人有年龄名字等属性,这些属性就定义为成员变量,写在构造函数中.并私有化防止对象直接访问,但加不加静态得看是否需要类直接调用,或者有没有其他静态方法来调用.
(九)构造代码块
举例:
class Person
{
private String name;
private int age;
Person()
{
System.out.println("A:name="+name+","+"age="+age);
}
{
cry();//这个就是构造代码块,没有名字,只有中括号和里面的语句.
}
Person(String n)
{
name=n;
System.out.println("B:name="+name+","+"age="+age);
}
Person(String n,int a)
{
name=n;
age=a;
System.out.println("C:name="+name+","+"age="+age);
}
public void cry()
{
System.out.println("cry...");
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person();
p1.cry();
Person p2=new Person("张三");
Person p3=new Person("李四",20);
}
}
结果为:
cry...
A:name=null,age=0
cry...
cry...
B:name=张三,age=0
cry...
C:name=李四,age=20
小结:构造函数代码块和构造函数的区别,以及构造代码块的特点:
构造函数代码块是给所有对象统一进行初始化,并且优先于构造函数执行,所以结果里面每一个对象的前面都有一个cry...,
构造函数是给对应的对象进行初始化.构造函数代码块用于定义每个对象的共性初始化值,所以上面代码的cry()是属于每个对象都要执行的行为,所以就写在构造函数代码块里面了.但是要注意构造函数代码块是优先于构造函数执行的,这些代码块执行完后会出现在每个构造函数的前面,注意代码块执行完后出现的位置.
(十)this关键字
当局部变量和成员变量名字相同时,对象会调用局部变量,而不会找成员变量.
举例:
class Person
{
private String name;
private int age;
Person(){}//注意这里这个空参数的是不能省略的,道理就是之前讲的如果自定义了构造函数,系统不会默认指定空参数的构造函数.
Person(String n)
{
name=n;
}
Person(String n,int a)
{
name=n;
age=a;
}
public void speak()
{
System.out.println("name:"+name+","+"age:"+age);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person();
Person p2=new Person("张三");
p1.speak();
p2.speak();
}
}
假如把
Person(String n)
{
name=n;
}
里面的n改成name,改的原因是为了直观,提高阅读性,好清楚到底对象要往这个构造函数里面传一个什么值.
Person(String name){
name=name;
}
此时的结果会显示
name:null,age:0
name不是对象传了个"张三"进去,怎么会显示null,原因就是,这里的成员变量和局部变量同名了,到底对象传的值要传给哪个name呢,哪个name是成员变量,哪个是局部变量,系统默认假如在函数里面的两个变量同名,那这两个都是局部变量,也就是说两个name都是一样,假如不同名,才会去成员变量中找.
要解决这个同名的问题,需要在成员变量的前面加一个关键字this声明,那么就应该这样写:
Person(String name)
{
this.name=name;
}
小结:this代表其所在函数所属对象的引用.换句话说,this就代表正在调用这个函数的对象名.
举例:
class Person
{
private String name;
private int age;
Person(String name)
{
this.name=name;//谁的对象在调用这个函数,this就代表那个对象的引用,比如p1是new Person("张三");这个对象的引用,如果p1在调用这个函数,那么this就代表p1.
}
public void speak()
{
System.out.println("name:"+name+","+"age:"+age);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person("张三");
Person p2=new Person("李四");
p1.speak();
p2.speak();
}
}
结果是
name:张三,age:0
name:李四,age:0
分析原因:p1把"张三"传给了Person(String name)里面没加this的那个name,这个name再赋值给了加了this的name,此时p1的name属性就有了值为"张三",所以p1在speak()的时候就是张三,age没传值进去,初始化是0,然后p2传了"李四"给局部变量name,再赋值给成员变量name,p2的name属性就是"李四",所以说this就代表所在函数所属对象的引用.当然在描述的时候给speak ()里面的name和age加上this声明更好,就写成 System.out.println("name:"+this.name+","+"age:"+this.age);同样在调用其他方法的时候,为了更加明确,也可以加上this,但是最好省略,因为没必要加,但是变量同名,就必须加了,不然计算机不能分辨哪个是哪个,比如
public void speak()
{
System.out.println("name:"+this.name+","+"age:"+this.age);
this.show();//this加了更加明确,但最好省略
}
public void show()
{
System.out.println(this.name);
}
注意:不管是对象还是其他什么,只要是在调用函数的时候,括号里面参数一定要和被调用函数定义的参数一致,如果是空参数,那么主动调用的那个括号里面也是空的,如果被调用的函数定义了参数类型,那么主动调用的那个括号里面也必须符合这个类型.在对象调用类里面函数的时候要尤其注意.
(十一)this关键字的应用
/*需求:给人定义一个用于比较年龄是否相同的功能.也就是是否是同龄人.
*/
class Person
{
private int age;
Person(int age)
{
this.age=age;
}
public boolean compare(Person p)//Person类型.
{
return this.age==p.age;//this代表p1,p代表p2.
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person(20);
Person p2=new Person(25);
System.out.println(p1.compare(p2));
}
}
小结:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象.比如下面compare这个函数要调用p1和p2这两个对象,一个就用this来声明,一个就用p这个变量来声明,但凡本类功能内部使用到了本类对象,都用this 表示.
(十二)this关键字在构造函数间调用
举例:
class Person
{
private int age;
private String name;
Person(int age)
{
this.age=age;
}
Person(String name,int age)
{
this.age=age;
this.name=name;
}
public int getAge()
{
return age;
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person("李四",20);
System.out.println(p1.getAge());
}
}
上面的两个构造函数中都有this.age=age这个操作,重复了,所以可以在下面的构造函数里面调用上面写好的this.age=age,
class Person
{
private int age;
private String name;
Person(int age)
{
this.age=age;
}
Person(String name,int age)
{
this(age);//这里的this指p1这个对象.
this.name=name;
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p1=new Person("李四",20);
System.out.println(p1.getAge());
}
}
传递分析:Person p1=new Person("李四",20);里面的20先传给age,再给age,再给age,再给age,再给age,这才传到p1的age属性里面.需要注意的就是这个this语句必须写在第一行,另外括号里面必须和要引用的哪个构造函数里面的参数要类型一致.比如这个age和这个age类型一致,也就是之前说到的调用函数要保证参数类型一致.
比如:
Person()
{
this("李四");
}
Person(String name)
{
this();
}
this() 再调用Person(),this("李四")又在调用Person(String name),这是个死循环.
小结:this语句用于构造函数间函数互相调用,是不能用于一般函数的,只能用于构造函数之间的调用.this语句只能定义在构造函数的第一行.因为如果初始化函数里面还有初始化,那就要先执行里面的那个初始化.java的this关键字只能用于方法的方法体内,当对象创建以后,jvm就会给这个对象分配一个引用自身的指针,这个指针就是this,也就是说this指针是在创建对象之后产生的.所以this只能在类的非静态方法中使用,静态方法和静态代码块中绝对不能出现this.并且this只和特定对象关联,不和类关联,同一个类不同对象有不同的this.
---------------------- android培训、java培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net/heima