那么什么是面向对象呢?
这里我们要引入一个面向过程的概念,因为面向过程和面向对象是息息相关的。
比如说举个例子,想干成一件事的话,那么有两种途径,要么自己做,要么别人帮你做,面向对象就好比你让别人来做这个事情,面向过程是无论谁做这个事情只要做了,也就是说,在处理问题时可以完全的面向过程,但是不能完全面向对象。
所以说可以把面向过程看成实现问题的解决,把面向对象看成实现问题的解决方案。实现问题有多种解决方案,但是最后肯定目的是为了解决问题,所以说抛出问题,一定就得需要面向过程。
面向对象的好处是可以有效的帮助开发大规模的软件以及图形用户界面。(通俗来说就是能实现更复杂的业务逻辑)
对象的具体含义
对象可以说是明确标识的一个实体,例如:一个学生,一张桌子,一个球等等都可以看成是一个对象,每个对象都有自己独特的标识,状态,行为。
- 一个对象的状态(也叫特征或者属性)都是由具体当前的数据域来表示的。例如:矩形对象具有数据域width和height,他们都是描述矩形的属性。
- 一个对象的行为(也叫动作)是由方法定义的,调用对象的一个方法就是要求对象完成一个动作。例如:可以为圆对象定义一个名为getArea()的方法,圆对象可以调用这个方法返回圆的面积。也可以定义其他的方法,圆对象也可以调用。
类的具体含义
类主要描述 属性-数据-成员变量 行为-函数-成员函数
类是对对象的抽象。类是一种抽象的数据类型。
对象和类的关系:对象是类的实例,类是对象的模板。
举例来说一下如何描述一个坐标
在面向过程的思想里面
int x,y;
int[] point={1,2};
额外的 如果是一组坐标
int x1,y1,x2,y2,x3,y3....
int[][] points={{1,2},{3,4},{5,6}};
其次对于他们之间的操作
getDistance(p1,p2) 求两点间的距离
弊端就是不方便统一管理
在面向对象的思想里面
p1=创建一个Point对象并且制定x=1,y=2
p2=创建一个Point对象并且指定x=3,y=4
p1.x p1.y
p1.getDistance(p2) 让p1自己去和p2之间计算距离
好处在于将数据和操作统一起来了
意味着将点拟人化 该事物的数据和操作就可以统一起来了
用代码实现
主函数
class lei{
public static void main(String[] args){
Point p1=new Point();
Point p2=new Point();
p1.x=10;
p1.y=20;
p2.x=30;
p2.y=40;
System.out.println(p1.getDistance(p2));
System.out.println(p2.getDistance(p1));
}
}
Point类
class Point{
double x;
double y;
public double getDistance(Point other){
return Math.hypot(x-other.x,y-other.y);
}
}
对象的内存图解
先了解下这三个概念
堆区: 1.存储new出来的对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) ,堆中不存放基本类型和对象引用,只存放对象本身 。
栈区: 1.每个线程包含一个栈区,栈中只保存基础数据类型的值和对象以及基础数据的引用2.每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。 3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
方法区: 1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。 2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
对象的内存图:
首先JVM运行一个class文件时,使用类加载器先将Demo类加载到方法区,然后main方法压栈(入栈)。
·在栈中运行main方法,当jvm看到Phone时,会自动把Phone类加载到方法区;当看到局部变量p时,会在栈中开辟一块空间;当看到new Phone()时,会在堆内存中开辟空间,并将堆内存中的对应地址0x123赋值给p;还会拿到方法区的地址值指向方法区。
·在main方法中运行到给对象p的属性赋值时,通过地址去堆内存中找到相应属性并赋值,运行p.sendMessage()这一步时,也是根据地址值去堆内存中找到相应的对象,再用对象去方法区中找到sendMessage()方法,然后将sendMessage()方法压到栈中(入栈),调用完毕sendMessage()方法会出栈。
·main方法运行结束后会出栈。
通过以上步骤描述,可以理解为,在栈内存中运行的方法,遵循"先进后出,后进先出"的原则。变量p指向堆内存中的空间,寻找方法信息,去执行该方法。
封装与private关键字
private关键字是一个权限关键字 public proteted默认不写的
private关键字 表示私有权限 该成员变量或成员函数只能够在类中被访问 外界不可访问
为了防止出现赋予错误值而引起的程序后期运行结果的错误,并且加private能修改也能获取的方法就是加一个setter修改器(主要负责修改成员变量),本身就是一个函数 setXxx形式 ,getter访问器(主要负责访问成员变量)getter不一定必须有 看情况
面向对象三大特征:封装,继承,多态
封装:即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
好处:是节约代码量,方便管理,降低耦合性。
代码中的体现
循环:主要解决有规律且重复性执行的代码
函数:主要解决具有独立功能的一段代码 后期进行复用即可
数组:主要解决多种同类型数据的操作 统一操作 方便类管理
类:主要将数据和行为进行统一方便操作 仿真现实中的事物
成员变量和局部变量的区别是
1.存储位置
局部变量存储在栈内存中函数的所属空间里
成员变量存储在堆内存中对象的所属空间里
2.生命周期
局部变量随着函数的进栈而存在,随着函数的弹栈而消失
成员变量随着对象的创建而存在,随着对象的销毁而消失
3.访问范围
局部变量的访问范围仅仅在函数当中
成员变量的访问范围在当前类中
4.初始化值
局部变量必须先进行初始化 之后再能被调用
成员变量在创建时有默认初始化
构造函数
构造函数存在意义就是在于:在创建对象时对成员变量进行赋值操作
格式:
权限修饰符 函数名(参数列表){ //public Classname(int age){}
函数体;
}
它的特点:没有函数类型关键字,没有返回值类型(但是能返回)这里函数名必须是类名。
注意:如果类中没有定义任何构造函数的情况下,则会有一个默认无参的构造函数,这里要说的是,如果创建的对象其中的有参和无参的话,默认走有参,在类中定义构造函数,但是无参的对象找不到相应的构造函数,因为一旦有明显定义的构造函数的话,那么默认的无参构造函数就不存在了,所以我们构造函数时一定把无参的构造函数写出来,防止被“覆盖”。
构造函数和成员函数的区别
构造函数只在创建对象的时候进行调用,而且只调用一次
成员变量在创建对象之后调动,可以调用任意次数。
成员函数可以调用成员函数,成员函数不可以调用构造函数,构造函数可以调用构造函数(减少代码的冗余,提高函数的利用率)一般是参数较少调用参数较多的函数,
注意:成员函数和构造函数重名 this(...)对this的调用必须是构造器中的第一个语句,放在最顶层。
class Test02{
public static void main(String[] args){
Demo d1=new Demo();
Demo d2=new Demo(10);
Demo d3=new Demo(10,20);
Demo d4=new Demo(10,20,30);
}
}
class Demo{
int a;
int b;
int c;
public Demo(){
this(0,0,0);
}
public Demo(int a){
this(a,0,0);//Demo(a,0,0);
}
public Demo(int a,int b){
this(a,b,0);//Demo(a,b,0);
}
public Demo(int a,int b,int c){
this(a,b,c);//Demo(a,b,c)
}
public void Demo(int a,int b,int c){
}
public void show(){
System.out.println(a+","+b+","+c);
}
private void init(){
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
System.out.println(".....");
}
}
其实构造函数存在不影响修改器个访问器的存在,如果数据后期需要被修改则添加。
对象的内存图解2
成员变量的赋值其中经历了三个阶段:默认初始化-显示初始化-针对性初始化
1.在堆内存中开辟一个空间并分配地址
2.对成员变量进行【默认初始化】
3.相应的构造函数进栈 刚开始就对成员变量进行【显式初始化】
4.接着再去执行构造函数中的内容【针对性初始化】
5.构造函数执行完毕 弹栈 将对象的地址赋值给相应变量即可