----------------- android培训、java培训、期待与您交流! ----------
面向对象
1 面向对象概念
1.面向对象概念:
面向对象和面向过程都是一种思想,面向对象相对于面向过程而言,是基于面向过程。
1.面向过程:强调功能行为(c语言)
2.面向对象:将功能封装进对象,强调具备功能的对象(java、c++、c#)
exp-
将大象装进冰箱
面向过程:1.打开冰箱2.存储大象3.关上冰箱;强调的是“打开”“存储”“关上”等功能行为
面向对象:1.冰箱打开2.冰箱存储3.冰箱关上;主体是冰箱,我们只需要让冰箱具有上述行为即可。
2.面向对象特点:
面向对象将功能封装进对象,可以将复杂的事情简单化,程序员由执行者进化为指挥者,而且不同对象具有特定功能,提高了复用性
3.面向对象特征:
封装(encapsulation)、继承(inheritance)、多态(polymorphism)
ps.
开发实质就是:找对象、创建对象、指挥对象、维护对象之间的关系
2 类和对象
类:对现实事物的描述,具体事物的抽象
对象:这类事物实实在在存在的个体
1.类的定义:
描述事物:事物的属性、事物的行为
对应到JAVA中:用class类来描述事物:成员变量(事物的属性)、成员函数(事物的行为)
因此定义类就是定义类中的成员变量和成员函数
2.成员变量和局部变量的去边
成员变量:
1. 成员变量定义在类中,在整个类中都可以被访问。
2. 成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
3. 成员变量有默认初始化值。局部变量:
1. 局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
2. 局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
3. 局部变量没有默认初始化值。
3.创建对象:
/*
* 描述小汽车
* 分析:
* 1. 属性。
* 轮胎数。
* 颜色。
* 2. 行为
* 运行。
*
* 定义类其实就是在定义类中的成员(成员变量、成员函数)。
*/
//对Car这类事物进行描述
class Car
{
//成员变量
String color = "red";
int num = 4;
//成员方法
void run()
{
System. out.println("color: " +color +"...num :" +num);
}
}
class Test
{
public static void main(String[] args)
{
//通过new关键字,建立对象
//c就是一个类类型的引用变量,指向了该类的对象
Car c1 = new Car();
c1.color="blue";
c1.run();
Car c2=new Car();
c2.run();
}
}
运行结果:
ps.对应的内存结构示意图
1、只要是用new操作符定义的实体就会在堆内存中开辟一个新的空间,并且每一个对象中都有一份属于自己的属性。
2、通过对象.对象成员的方式操作对象中的成员,对其中一个对象的成员进行了修改,和另一个对象没有任何关系。
3、c1、c2都是对实体的引用变量,如果执行c2 = c1,那么c2也就指向了c1引用的实体。c2原来引用的实体因为没有被引用变量引用,就会被垃圾回收器回收
4.匿名对象
对象的简化形式
使用情形:
a、只需要调用对象方法一次
b、做为实际参数进行传递
class Car
{
//成员变量
String color = "red";
int num = 4;
//成员方法
void run()
{
System.out.println("color:"+color+"...num:"+num);
}
}
class Test
{
public static void main(String[] args)
{
//使用匿名对象对对象方法调用一次
new Car().run();
//匿名对象做为实际参数传递
show(new Car());
}
public static void show(Car c)
{
c.color="blue";
c.num=8;
System.out.println("color:"+c.color+"...num:"+c.num);
}
}
运行结果:
3 构造函数
特点:
1、函数名与类名相同
2、不用定义返回值类型
3、不可以写return语句
作用:
给对象进行初始化
public class Test {
public static void main(String[] args) {
Student s=new Student();//创建对象
}
}
class Student
{
Student(){
System.out.println("student run");
}
}
运行结果
ps.
1.对象一建立就会调用与之对应的构造函数
2.当一个类中没有定义构造函数时系统会默认加一个空参数的构造函数:类名()
public class Test {
public static void main(String[] args) {
Person s=new Person();
Person s1=new Person("lisi");
Person s2=new Person("zhangsan",20);
}
}
class Person
{
private String name;
private int age;
Person()//没有名字,没有年龄
{
System.out.println("A:name="+name+"...age="+age);
}
Person(String s)//有名字,没有年龄
{
name=s;
System.out.println("B:name="+name+"...age="+age);
}
Person(String s,int a)//有名字有年龄
{
name=s;
age=a;
System.out.println("B:name="+name+"...age="+age);
}
}
运行结果:
ps.
以上程序如果注释掉空参数的构造函数时,会报错,这是因为构造函数已经被重载,系统不会默认添加构造函数了
一般函数和构造函数的区别:
1、写法不同
2、运行上不同
a、构造函数对象一建立就运行,给对象初始化
b、一般函数要对象调用才运行,给对象添加功能
c、一个对象建立构造函数只运行一次
d、一个对象建立一般函数可以被调用多次
综上:分析事物时,该事物具备一些特性,可以将这些特性定义在构造函数中,需要未知内容参与运算则加入参数
4 构造代码块
作用:给所有对象进行初始化
ps.
构造函数和构造代码块的区别:
1、对象一建立构造代码块就运行且优先于构造函数执行
2、构造代码块是给所有对象进行统一初始化,而构造函数是给与之对应的对象初始化
<span style="font-size:12px;">public class Test {
public static void main(String[] args) {
Person s=new Person();
Person s1=new Person("lisi");
}
}
class Person
{
private String name;
private int age;
//构造代码块,对象一建立就运行,且优先于构造函数
{
System.out.println("person cry");
}
Person()//没有名字,没有年龄
{
System.out.println("A:name="+name+"...age="+age);
}
Person(String s)//有名字,没有年龄
{
name=s;
System.out.println("B:name="+name+"...age="+age);
}
}</span>
运行结果:
5 this关键字
this:本类对象的引用(哪个对象在调用this所在的函数,this就代表哪个对象)
ps.
可以用于区分成员变量和局部变量重名
public class Test {
public static void main(String[] args) {
Person s=new Person("lisi",20);
s.speak();
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)//有名字,没有年龄
{
name=name;//函数先找局部变量再找成员变量,因为重名,所以name并没有赋值给对象s
this.age=age;//将age赋值给调用函数的本类对象的age
}
public void speak(){
System.out.println("B:name="+this.name+"...age="+this.age);
}
}
运行结果:
this可用于构造函数间的相互调用看
ps.
只能定义在第一行,因为初始化要先执行,否则会报错
public class Test {
public static void main(String[] args) {
Person s=new Person("lisi",20);
s.speak();
}
}
class Person
{
private String name;
private int age;
Person(String name)
{
this.name=name;
}
Person(String name,int age)
{
this(name);//p(name)构造函数间的相互调用,注意格式是没点(.)
this.age=age;
}
public void speak(){
System.out.println("B:name="+this.name+"...age="+this.age);
}
}
6 static关键字
static关键字:用于修饰成员(成员变量和成员函数)。
static修饰的成员具备以下特点:
1、随着类的加载而加载。
2、优先于对象存在。
3、被所有对象所共享。
4、可以直接被类名调用。
5、存在于方法区(共享区)
<span style="font-size:12px;">public class Test {
public static void main(String[] args) {
Person p=new Person();
p.speak();
System.out.println("被对象调用"+p.country+"...被类名调用"+Person.country);
}
}
class Person
{
String name;//成员变量、实例变量
static String country="CN";//静态变量、类变量,所有对象所共享
public void speak(){
System.out.println("country="+country+"...name="+name);//实际为:System</span><span style="font-size:12px;">.out.println("country="+Person.country+"...name="+this.name)</span><span style="font-size:12px;">
}
}</span>
运行结果:
成员变量和静态变量的区别?
1. 两个变量的生命周期不同
成员变量随着对象的创建而存在,随着对象被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2. 调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3.数据存储位置不同
成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
静态的使用的注意事项:
1.静态方法只能访问静态成员
2.静态方法中不能使用this关键字
ps.
静态方法和静态变量存在时还没有建立对象,自然无法访问非静态
public class Test {
public static void main(String[] args) {
Person p=new Person();
p.speak();
System.out.println("被对象调用"+p.country+"...被类名调用"+Person.country);
}
}
class Person
{
String name;//成员变量、实例变量
static String country="CN";//静态变量、类变量,所有对象所共享
public static void speak(){
System.out.println("country="+country);
System.out.println("name="+name);
}
}
ps.
静态的使用场景
1. 静态变量
当分析对象中所具备的成员变量的值都是相同时,这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。
如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。
2. 静态函数
函数是否用静态修饰,就参考一点,就是该函数功能是否需要访问到对象中的特有数据。
简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。
如果不需要,就可以将该功能定义成静态的。当然,也可以定义成非静态,但是非静态需要被对象调用。
如果没有访问特有数据的方法,该对象的创建是没有意义
7 主函数
主函数是静态的,主函数特殊之处:
1. 格式是固定的。
2. 被jvm所识别和调用。
主函数各成分解析:
public:权限必须是最大的,被jvm调用。
static:不需要对象调用,直接用主函数所属类名调用即可。 命令行窗口中输入:java StaticDemo,实际上就是在执行StaticDemo.main();。
void:主函数不需要具体的返回值。
main:函数名,不是关键字,只是一个jvm识别的固定的名字。
String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。
class MainDemo{
public static void main(String[] args){
for(int x = 0; x < args.length; x++){
System.out.println(args[x]);
}
}
}
运行结果:
总结、扩展
1、对象的初始化:
a、单独一个对象初始化:静态对象→非静态对象→构造函数
b、包含继承的子类初始化:父类静态代码块→子类静态代码块→父类代码块→父类构造函数→子类代码块→子类构造函数
c、包含继承和多态的子类初始化:父类静态成员→父类静态代码块→子类静态成员→子类静态代码块→父类代码块→父类构造函数→子类代码块→子类构造函数
2、java的内存机制
程序计数器:当前线程所执行的字节码的行号指示器
Java虚拟机栈:描述Java方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。
本地方法栈:为虚拟机使用的native方法服务。
Java堆:被所有线程共享的一块内存区域,在虚拟机启动时创建。所有的对象实例以及数组都要在堆上分配。
方法区:线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量即时编译器编译后的代码数据等(这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载)。