〇、说明
本章内容能理解多少就理解多少,对于初学者不能全部理解也很正常,只要开发时间长了就能突然醒悟了。
一、面向对象简述
面向对象是一种现在最为流行的程序设计方法,几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。
但是在面向对象设计之前,广泛采用的是面向过程,面向过程只是针对于自己来解决问题。面向过程的操作是以程序的基本功能实现为主,实现之后就完成了,也不考虑修改的可能性,面向对象,更多的是要进行子模块化的设计,每一个模块都需要单独存在,并且可以被重复利用,所以,面向对象的开发更像是一个具备标准的开发模式。
------------------------------------(摘抄)
在面向对象定义之中,规定了JAVA面向对象的三个基本特征:
(1)封装:保护内部的操作不被破坏;
(2)继承:在原本的基础之上继续进行扩充;
(3)多态:在一个指定的范围之内进行概念的转换。
这些将在以后的章节详细讲解。
对于面向对象的开发来讲也分为三个过程:OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象编程)。
二、对象与类的基本概念
在现实世界中的所有实物都能转化为java中的对象,所以我用两者对比,直观的了解对象。
从上面可以看出,对象里面最基本的是属性和方法。对象是整个面向对象编程中最基础的组成单元。在java中,万物皆对象。
在之前的章节中,我们建的所有类(class),实际上都是一个个的对象,对象里面有一个main方法,是我们开始程序的地方,如果 类中没有main方法,类就无法单独运行。,简单的说类就是对象,但对象不一定是类(如interface),我在以后的章节中,不管说“新建一个类”还是说“新建一个对象”,他们差不对是一个意思。
三、对象的定义
对象中,可以有一个或多个属性、方法,也可以没有任何的属性方法,以下定义都是合法的:
public class Person {
String name = "张三";
int age = 37;
char sex = '男';
}
public class School {
public void getSchoolName() {
System.out.println("河南工业大学");
}
public String getFacultyNmae() {
return "软件学院";
}
}
public class HeiHei {
}
String是一个字符串对象(或者字符串类),用来存储字符串。它跟8种基本类型不一样,它有很多的方法,而8种基本类型没方法没属性,所以基本类型不是对象。
四、对象的使用
下面是一个简单的例子,定义一个类,调用方法,打印类中的参数:
public class JiSuan {
int a = 10;
int b = 5;
/**
* 定义一个计算a+b并打印结果的方法
*/
public void jiSuan() {
int sum = a + b;
System.out.println("a+b=" + sum);
}
public static void main(String[] args) {
JiSuan jiSuan = new JiSuan();
//调用jiSuan方法
jiSuan.jiSuan();
//打印对象中a的值
System.out.println("a=" + jiSuan.a);
//修改对象中a的值
jiSuan.a = 666666;
System.out.println("a=" + jiSuan.a);
}
}
这里面引入了一个新的关键字:new。在这段代码里,我们新建了一个对象(类)JiSuan。在main方法里面,需要先定义一个“JiSuan”类型的对象(或者称之为对象变量),定义的方法跟定义基本类型相似(int a = 1;),只不过“=”后面我不是直接赋值,而是使用了new。对象中有两个极为重要的概念:堆、栈。
相当于在栈中声明了一个名字为jiSuan的JiSuan对象,相当于在堆中申请了一个新的空间(新的内存地址),在这个空间中才是存放方法和属性的地方,意思是在堆中申请了一个新的空间,并把空间地址保存在名字为“jiSuan”的栈中。几乎所有的对象定义都是这样的过程,代码很简单,不过需要记住其原理。
定义一个完整的方法,一般是“作用域 返回值类型 方法名(参数){}”:
作用域:常用的是public,直译为公共的。意思是该属性或者方法使用范围,public定义的属性、方法,可以在任意地方使用,比如可以被其他类调用。相对的还有private,直译为私有的,只能在定义的类中使用以后章节会详细讲解。
返回值类型 :方法直接结束返回的类型,之前定义的是void,直译为空,意思是不反悔任何值。如果把void改为int或者String,就能通过return返回相应类型的值。
方法名:没特殊要求,一般是驼峰命名法即可,根据java规范,变量名、方法名一般用字母、数字、下划线组成,开头可以是下划线,但一定不能是数字。
参数:上面的代码中,小括号里是没有任何东西的,表示不需要传参,也可以在这里面定义一个或多个变量,用来接收外部调用方法时传入的参数。
当定义好jiSuan后,只需要通过运算符“.”调用就行了,如“.属性”、“.方法”,或者直接修改属性。
定义和使用一个传参并带有返回值的方法:
public class JiSuan {
int a = 10;
int b = 5;
/**
* 定义一个计算a+b并返回结果
*/
public int jiSuan() {
int sum = a + b;
return sum;
}
/**
* 传入年龄和名字,返回拼接好的字符串
*/
public String getNameAndAge(int age, String name) {
return name + "今年" + age + "岁";
}
public static void main(String[] args) {
JiSuan jiSuan = new JiSuan();
System.out.println("a+b=" + jiSuan.jiSuan());
String str = jiSuan.getNameAndAge(18, "小明");
System.out.println(str);
}
}
上面的代码中,有返回值的方法,最终是通过return把值传(返回)出来的。
下面再写一个复杂一点的对象,演示方法之间相互调用:
public class JiSuan {
public int jiSuan(int a, int b) {
int sum = a * b;
return sum;
}
public String getNameAndAge(int age, String name, int a, int b) {
return name + "今年" + age + "岁,他计算出了" + a + "乘以" + b + "的结果了:" + jiSuan(a, b);
}
public static void main(String[] args) {
JiSuan jiSuan = new JiSuan();
String str = jiSuan.getNameAndAge(5, "小明", 123, 456);
System.out.println(str);
}
}
可以看出,同类中方法之间的调用,直接调用就行了,不需要new,在main方法中不可以直接调用getNameAndAge()、jiSuan(),其主要原因是main方法是一个静态关键字定义的方法(static),称为静态方法,相应的还有静态属性。静态方法可以直接调用静态方法或静态属性,非静态方法可以直接调用静态或非静态定义的属性和方法,静态方法如果想调用非静态定义的属性和方法,必须通过new定义一个变量之后才能调用。
先深刻领悟下面的例子:
public class JiSuan {
static int a = 0;
int b = 1;
public static void a() {
System.out.println("a()");
}
public void b() {
System.out.println("b()");
}
/**
* main方法本身就是一个静态方法
*/
public static void main(String[] args) {
//mian可以直接调用static定义的方法或属性
a();
JiSuan.a();
System.out.println(a);
System.out.println(JiSuan.a);
System.out.println("--------------------------------------------");
//mian不能直接调用b(),因为b是非静态
JiSuan js = new JiSuan();
js.b();
System.out.println(js.b);
}
}
但千万不要为了不new,把所有的方法和属性全都定义为静态,觉得直接调用很方便,static不是这样用的!程序在启动的时候,会自动把static定义的属性和方法直接放进内存中,所以你在任何地方都可以直接调用,这种做法只会造成内存不必要的开销!只有定义为非静态,用对象的时候用new申请一个内存空间,才是正确的做法。通常在“工具类”中才会经常定义静态方法。
但千万不要写出如下代码,a()与b()相互调用,造成堆栈溢出。
public class JiSuan {
public void a() {
System.out.println("进入了a方法");
b();
}
public void b() {
System.out.println("进入了b方法");
a();
}
public static void main(String[] args) {
JiSuan jiSuan = new JiSuan();
jiSuan.a();
}
}
上面说到,new是申请了新的空间,我们可以用代码验证下:
public class JiSuan {
int a = 0;
int b = 1;
public static void main(String[] args) {
JiSuan js1 = new JiSuan();
JiSuan js2 = new JiSuan();
//比较js1和js2
System.out.println(js1 == js2);
//修改js1的属性
js1.a = 999;
//修改js1.a并不会影响js2.a
System.out.println(js1.a);
System.out.println(js2.a);
}
}
最后打印了false。对象的比较不同于基本类型的比较,基本类型是值比较,只要值相等就是相等的,基本类型没有堆,只有栈,即没有空间(地址)。对象的比较是基于内存地址的比较,js1和js2,都是通过new申请的新的内存地址,所以它俩不相等,修改js1并不会影响到js2。
一个完整的java程序是需要很多类相互协作运行的,就如同一个人,包含眼、口、舌、心、肝、肺、手脚、血液,每一个人体器官都可以看作是一个java中的类(对象),它们有各自的功能,相互协作才能够展现一个活生生的人。所以说在java中,万物皆对象!
作业:
1、定义A、B、C三个类:C类定义属性c并赋值,定义一个方法c(),传入一个int型参数,与属性c计算乘积,返回int型数据;B类定义一个方法b(),定义一个属性b并赋值,在b()中调用C类方法c()并打印返回值;A类定义一个方法a(),调用B类方法b()和打印B类属性b,最后只运行A类main方法,调用a(),在此定义过程中不可使用static。(因为最后只运行A类,所以B、C类可以不定义main方法)
上节作业答案:
1、3、5略。
2、
public class HomeWork {
public static void main(String[] args) {
int a = 23;
int b = 55;
int c;
c = a > b ? (a - b) : (b - a);
System.out.println("a与b相差" + c);
}
}
4、
package com.hjgzj.guess;
import java.util.Scanner;
/**
* 这是一个猜数字的程序
*
* 作者:https://blog.csdn.net/hjgzj/article/category/6412075
*/
public class GuessTheNumber {
public static void main(String[] args) {
System.out.println("猜数字:");
try {
while (true) {
System.out.println("请选择难度:1简单、2、困难。随时输入-1退出程序!");
//创建一个能从控制台获取输入流的对象。
Scanner scanner = new Scanner(System.in);
int count = 0; //一个允许猜的次数
int guessCount = 0; //剩余次数
int level = 0;
while (true) {
level = scanner.nextInt(); //从控制台获取输入的数字赋值给level
if (level == 1 || level == 2 || level == -1) {
break;
}
else {
System.out.println("选择有误,请重新选择");
System.out.println("请选择难度:1简单、2、困难。随时输入-1退出程序!");
}
}
if (level == 1) { //选择1可以猜10次
count = 10;
guessCount = 10;
}
else if (level == 2) { //选择2可以猜5次
count = 5;
guessCount = 5;
}
else if (level == -1) { //选择-1结束程序
System.out.println("程序结束!");
System.exit(0);
}
int randomNum = (int)Math.round(Math.random() * 100); //获取一个随机整数,范围是[0-100]
boolean bingo = false; //如果猜对了,就是true。
for (int i = 0; i < count; i++) { //根据选择的次数循环。
System.out.println("请输入一个0-100的数字");
int inputNum = scanner.nextInt(); //从控制台获取输入的数字
if (inputNum == -1) { //-1程序结束
System.out.println("程序结束!");
System.exit(0);
}
else if (inputNum == randomNum) { //判断输入的数字等于随机的数字,就是猜对了。
bingo = true; //然后把bingo改为true,表示已猜对。
break; //最后用break结束整个for
}
else { //如果上面的条件都不符合
guessCount--; //把剩余次数自减1,这个相当于guessCount = guessCount - 1;
System.out.println("你猜的数字" + (inputNum > randomNum ? "大" : "小") + "了,剩余次数" + guessCount);
}
}
if (bingo) {//循环结束之后,判断是否猜对过
System.out.println("你猜对了,这个数字是" + randomNum + "!\n");
}
else {
System.out.println("次数全部用完,你没有猜对过!\n");
}
}
}
catch (Exception e) {
System.err.println("你输入的不是整数,程序结束!");
}
}
}