面向对象
对于java初学者而言,来到面向对象这章而言,肯定会有许多困惑,比如:对象是什么?对象是怎么创建的?对象可以用来干什么、为什么要面向对象?而不是基于面向对象,更有人会对面向过程和面向对象这两概念产生混淆,接下来就来跟我一起解决这些问题。
首先我们先把这个易混淆概念来讲解一下,不懂的同学可以先听一下,听完这些在解决其他问题,可能会有更大的帮助。
面向对象思想
面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;这种思想是将数据作为第一位,而方法或者说是算法作为其次,这是对数据一种优化,操作起来更加的方便,简化了过程。面向对象有三大特征:封装性、继承性、多态性,其中封装性指的是隐藏了对象的属性和实现细节,仅对外提供公共的访问方式,这样就隔离了具体的变化,便于使用,提高了复用性和安全性。对于继承性,就是两种事物间存在着一定的所属关系,那么继承的类就可以从被继承的类中获得一些属性和方法;这就提高了代码的复用性。继承是作为多态的前提的。多态是说父类或接口的引用指向了子类对象,这就提高了程序的扩展性,也就是说只要实现或继承了同一个接口或类,那么就可以使用父类中相应的方法,提高程序扩展性,但是多态有一点不好之处在于:父类引用不能访问子类中的成员的特有方法和属性。 |
封装思想
所谓封装,就是将属性和方法捆绑到一起,封装到一个对象中zhi去,简单的说,你是人,你有许多属性,比如说dao你的姓名,年龄,身高,体重,性别,性格,爱好等等,这是属性;而同时,你又会吃饭,睡觉,工作,学习,做事情,这些是方法,是你所具有的;同时将属性和方法封装到一个类中去,就能很完美的描述这个类的特征了,同时,它所具有的方法也就一起集成到类中,方便使用,这些是简单的描述了。官方一点说就是:封装是将事物的一些不便暴露给外界的一些属性隐藏起来.同时给外界提供一些接口,用来和外界进行交互,建立连接关系。 |
封装的优点:(1)隐藏类的实现细节;(2)让使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制 逻辑,限制对属性的不合理操作;(3)便于修改,增强代码的可维护性;
易混淆概念
“面向对象”和“基于对象”
面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些。
“面向对象”和“面向过程”
他们都是解决问题的思路(大致的方向),但是要他们对于同一问题的解决思路是不一样的。
可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。
如果是面向对象的设计思想来解决问题。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
简而言之:面向过程就是一个执行者,凡事都要自己亲力亲为;面向对象就是一个指挥者,需要让别人就帮你解决问题。
注意:高能预警!!!!!!
面向对象和面向过程一定是互斥的吗? 肯定不是。
我们在处理问题时可以完全的面向过程,但是不能完全面向对象,举个栗子:“你想吃饭”
你让女朋友做饭 你这个角度而言 面向对象
从女朋友这个角度而言呢?如果女朋友做---》面向过程;如果女朋友不做 叫外卖---》 面向对象
从餐馆这个角度而言呢?应该是要做饭---》 面向过程;如果餐馆不做 可以叫别家餐馆做---》面向对象
.....别的餐馆都不做 ,这个饭始终没人做, 相互踢皮球,最终问题也不会被解决
从中可以看出什么————这个事最终要被处理必须面向过程。
所以 面向过程其实是最基本的思路 而面向对象是基于面向过程的思路。
从上面的长篇巨幅了解完之后,对于我们学习java的,刚开始都是程序员,所以我们需要写很多代码,在宏观上而言,写代码啊就是在面向过程,只不过在某个时刻,某一行代码,我们会用到面向对象的东西。
System.out.println("来了老弟~");
//系统过来.输出.在控制台输出(输出打印的内容)
Scanner scanner=new Scanner(System.in);
//把那个扫描控制台的那个人给我叫过来 这个人的名字就是scanner
int a=scanner.nextInt();
//你让这个人从控制台读入一个整数并且给了变量a
Random random=new Random();
//把那个负责生成随机数的人给我叫过来 这个人的名字是random
int a=random.nextInt();
//让这个人给我生成一个随机的整数 给变量a
对象与类
面向对象有什么样的好处呢?
可以仿真的模拟现实生活中的事物,可以实现更加复杂的业务逻辑
淘宝在买东西的时候 查看商品->付款->生成订单->物流信息
如何描述一个坐标呢?
在面向过程的思想里面
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之间计算距离,好处在于将数据和操作统一起来了
意味着将点拟人化,该事物的数据和操作就可以统一起来了。
对象是什么?类是什么?
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。(大白话来讲就是真实存在且具体的事物,由某一个类所描述出来的具体的事物)
具有相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。(大白话来讲就是类主要用来描述事物,其实是事物的属性用数据来表示,事物的行为用函数来表示)
如果还太懂就记住这句话:类相当于大楼设计图纸,对象就是由该图纸所建成的大楼。
现在我们再来描述一个坐标
目前而言 但凡创建对象 用new关键字
格式:类名/数据类型 变量名=new 类名();
如何访问对象中的成员呢 变量名.成员
//属性 x y
//行为 getDistance()
class Point{//Point类
double x;//成员变量
double y;
public double getDistance(Point other){//成员函数
return Math.hypot(x-other.x,y-other.y);
}
}
class Test01{
public static void main(String[] args){
Point p1=new Point();
Point p2=new Point();
//System.out.println(p1.x);0.0
//System.out.println(p1.x);0.0
p1.x=10;
p1.y=20;
p2.x=30;
p2.y=40;
System.out.println(p1.getDistance(p2));
System.out.println(p2.getDistance(p1));//两结果是一样的
}
}
从上边两个代码可以看出当我们在创建一个类的时候 其实就是在自定义一个数据类型。
注意:建议一个类一个.java文件 方便类管理(不论是主类还是被调用的类),如果你偏要放在一起,也可以,编译后,会产生两个.class文件;
如果你遇到分开写两个类报错时,看一下你的系统环境变量里是否有ClassPath,有的话删掉,一路确定出来,重启cmd就可以了。这是因为ClassPath会自动调用java自己内部的类,你没导包自然会报错找不到符号。
对象的内存图解①
这里就不画常量池了。只画一下栈,堆,方法区。
不论几个对象,函数只加载一次。
步骤:
1.在堆内存中开辟一个空间并分配地址
2.按照类的描述,在该空间中定义成员变量,并且有默认初始化值
3.加载成员函数进入方法区(只加载一次)
4.对象加载完毕,将空间地址赋值给相应的变量
5.变量(p1/p2)调用成员函数
直接去方法区找该成员函数,将该函数加载进栈内存开始运行。
为了方便区分哪一个对象调用的该成员函数,有this这个关键字段,来区分this主要存的是当前对象的地址
注意:当成员函数在操作空间的时候,先在当前函数的空间里找局部变量,如果没有找到,再去this所指向的堆内存中对象所属空间里去找。
下面来练习一下,对照代码巩固一下对象的内存图解
class Test02{
/*
定义一个解决一元二次方程的类
数据
a,b,c,delt
行为
isSolved() 判断是否有解
getRoot1() 获取第一个解
getRoot2() 获取第二个解
QuadrationEquation
*/
public static void main(String[] args){
QuadrationEquation qe=new QuadrationEquation();
qe.a=10;
qe.b=50;
qe.c=5;
System.out.println(qe.isSovled());
System.out.println(qe.getRoot1());
System.out.println(qe.getRoot2());
}
}
class QuadrationEquation{
double a;
double b;
double c;
double delt;
public boolean isSovled(){
delt=b*b-4*a*c;
return delt>=0;
}
public double getRoot1(){
return (-b+Math.sqrt(delt))/(2*a);
}
public double getRoot2(){
return (-b-Math.sqrt(delt))/(2*a);
}
}
class Test03{
/*
点类Point
数据 x横坐标 y纵坐标
行为 getDistance(Point other) 返回当前点和传入点other之间的距离
三角形类Triangle
数据 Point p1,p2,p3
行为 getArea() 返回当前三角形的面积
getLength() 返回当前三角形的周长
*/
public static void main(String[] args){
Triangle t=new Triangle();
Point p1=new Point();
p1.x=0;
p1.y=10;
Point p2=new Point();
p2.x=0;
p2.y=0;
Point p3=new Point();
p3.x=10;
p3.y=0;
t.p1=p1;
t.p2=p2;
t.p3=p3;
System.out.println(t.getLength());
System.out.println(t.getArea());
}
}
class Point{
double x;
double y;
public double getDistance(Point other){
return Math.hypot(x-other.x,y-other.y);
}
}
/*
三角形类Triangle
数据 Point p1,p2,p3
行为 getArea() 返回当前三角形的面积
getLength() 返回当前三角形的周长
*/
class Triangle{
Point p1;
Point p2;
Point p3;
public double getArea(){
double side1=p1.getDistance(p2);
double side2=p1.getDistance(p3);
double side3=p2.getDistance(p3);
double s=(side1+side2+side3)/2;
return Math.sqrt(s*(s-side1)*(s-side2)*(s-side3));
}
public double getLength(){
return p1.getDistance(p2)+p1.getDistance(p3)+p2.getDistance(p3);
}
}
本人也是初学者,下一个博客再继续补充面向对象的知识,关注博主不迷路:https://blog.csdn.net/f1244313823