目录
如果创建了一个类的多个对象,每个对象都独立的拥有自己的一套类的属性。(非static属性)
前言:
骚年们,我AE86_HAN又回来了,面向对象课程得讲解也终于要开始了,说讲解也有些言过其实了,只是自己再次重写面向对象时,会有一些新的感悟与体验经验分享给大家,便于大家更快得理解面向对象得编程思想。
QAQ!!!
1.面向过程(POP)与面向对象(OOP)概述
1.1 二者都是一种思想,面向对象是相对于面向过程而言的。
面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
例:将大象装进冰箱这件事情
面向过程(强调怎么做):
(1)打开冰箱门
(2)把大象抬起来,塞进冰箱里面
(3)关闭冰箱门
显然,面向过程简单明了,更加得通俗易懂,我们想要完成一件特定得事务,我们需要考虑完成这个事务需要哪些步骤,而不必去纠结是谁完成得,直接可以在三个方法中完成整个过程。
面向对象(强调谁来做):
人{
打开冰箱(冰箱){
冰箱.开门();
}
进入冰箱(大象){
大象.进入();
}
关闭冰箱(冰箱){
冰箱.关门();
}
}
冰箱{
开门(){};
关门(){};
}
大象{
进入(冰箱){
}
}
这件事相对于面向对象得编程思想来说得话,完成一件具体事务,我们首先需要考虑完成这件事都需要哪些主体得对象,并且每个对象中都能定义实现哪些具体得方法,然后再将这些对象关联起来,就可以真正得完成一整件事务。
但是面向对象得编程思想肯定不可能就这样就理解透了,俗话说的好,熟能生巧,在之后得面向对象得知识得积累和代码积累,相信大家一定会对面向对象得编程思想有更深刻得认识!
思想概述:
1.2 Java语言的基本元素:类和对象
1.2.1 类(Class)和对象(Object)是面向对象的核心概念。
- 类是对一类事务的描述、是抽象的、概念上的定义(人们在一些具有相同属性和行为的个体上抽象出来的一个概念)
- 对象是实际存在的该类事务的每个个体,因而也称为实例(instance)(人们抽象出来的类的实实在在的一个个体)
重点来了!!!(核能警告)
(字挺大,还挺重):
面向对象的程序设计的重点就是类的设计
设计类,就是设计类的成员
所以嘞,啥玩意是类得成员鸭,韩韩百思不得其解!那么接下来就首先需要声明一些基本得概念:
属性 = 成员变量 = field = 域、字段
每一个人(对象、实例)做为人类抽取出来得个体,大家都会有名字鸭、年龄呀、身高、体重...,emmmm...说到痛点了,身高、体重就不是很优秀,这些通常讲得概念就是所谓得每个对象所具有得属性
方法 = 成员方法 = 函数 = method
方法就相当于一个对象所具有得一些个功能或者说掌握得本领(行为),例如:人都会吃饭、走路、睡觉,那么我们就可以对这些方法具体得定义
成员变量:只要是在类中定义的变量,就是成员变量
成员方法:只要是在类中定义的方法,就是成员方法
说明:创建类的对象 = 类的实例化 = 实例化一个类
前面声明了一些基本得概念,可有了这些概念有啥玩意用呀?我当时也和大家有一样得疑问,不要急,欲速则不达。咳咳咳,男人不能太快嘛!!!
那么接下来就为大家讲解类和对象得使用方法:
类和对象的使用(三步走策略):
1.创建类,设计类的成员(属性(成员变量)、方法(成员方法))
2.创建类的对象(类的实例化)(new + 类名得操作就是在创建一个类得对象)
3.通过"对象.属性"或者“对象.方法”对类中成员来进行调用
如果创建了一个类的多个对象,每个对象都独立的拥有自己的一套类的属性。(非static属性)
意味着:如果我们修改其中任意一个对象的属性age,对其他对象的属性age是没有任何影响的.因为这个属性是已经创建了对象独有得一套,你总不能说,我是我,你是你,你改了名字以后,我得名字就变了你改了以后得名字,实际上,咋两做为两个对象没有任何关系(相互独立得一个个体)。
首先对Java中得内存结构来做一下了解,我们才能更好得知道谁是谁,谁应该在哪里不是?
上面得图就是Java得内存结构图,看起来很高大声,有木有
接下来就对对象得内存空间做一下解析(以下述代码为例,没事相信你们可以举一反三):
(1)Person p = new Person();
(2)p.name = "Mike";
(3)Person p1 = new Person();
(4)System.out.println(p1.name);
(5)Person p2 = p;
(6)p2.age = 10;
(7)System.out.println(p.age);
内存图解:
详细创建步骤解析:
(1)赋值操作,都首先执行赋值号右边的语句,new + 类名,在堆内存中开辟空间,创建Person类的实例,并且分配随机的地址ox123,在对象实例里面放置的是对象的属性,并且进行了默认的初始化,将该对象的首地址赋给在主方法中的Person变量p的引用,p此时也就指向了ox123
(2) 通过引用p中存放该实例对象在堆内存中的首地址,找到该对象里面的字符串类型name属性,将其修改为"Mike"
(3)执行和1相同的操作,new + 类名就是创建对象的操作,该对象是一个新的对象,分配随机地址ox456,在对象里面存放对象的属性,并且进行了默认的初始化,将该对象的首地址赋给在主方法中的Person变量p1的引用,p1此时就只想了ox456
(4)调用p1当中的name属性,并进行输出,成员变量在创建的时候,都会经过默认初始化的阶段,那么name属性是String字符串引用数据类型的,又因为引用数据类型的默认值都是null,所以输出null
(5)赋值操作,从右向左进行,将引用p中存放的对象的首地址赋给Person类型的变量p2,那么p2和p就同时存放相同的首地址值,那么两变量都指向堆内存中的同一个对象实例
(6)p2通过首地址找到在堆内存中创建的Person类的对象,并对其中的整型属性age值赋值为10
(7)输出p引用下的对象的age值,因为p2没有重新创建新的对象,而是p和p2都指向堆内存中的相同的对象,那么引用变量p2对该对象的修改,是对所有指向该对象的引用都是有影响的,那么由于之前p2将age值改成了10,所以p.age也将读取并输出p2修改后的age值
1.3 类中属性得使用
属性(成员变量) VS 局部变量
1.相同点 :
1.1定义变量得格式相同:数据类型 变量名 = 变量值(可先声明,再赋值)
1.2先声明,后使用(很简单得道理,你都没告诉Java虚拟机你是谁,你就要进行一顿胡操作(输出或者赋值),显然不合适吧)
1.3变量都有其特定得作用域
2.不同点:
2.1在类中声明得位置不同
属性:直接定义在类得一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部得变量
2.2关于权限修饰符得不同
属性:可以在声明属性时、指明其访问权限、使用权限修饰符(可以简单得理解为使用了权限修饰符了以后外界对对属性得可见性得不同)
常见的权限修饰(由大到小进行排列):public - protected - default(属性默认访问权限、包访问权限) - private
局部变量:不可以使用权限修饰符的
2.3默认初始化值得情况
属性:类得属性根据其类型都有,都有默认初始化值
局部变量:没有默认初始化值,意味着必须声明并显式赋值之后才能进行调用。
特别的,形参在进行调用时,再进行赋值即可。
2.4在内存中加载得位置也是不同得
属性:加载到堆内存中对象得堆空间中(非static得)
局部变量:加载在方法所在得栈空间中
成员变量(属性)和局部变量使用定义使用得测试用例:
public class User_Test {
public static void main(String[] args) {
User user = new User();
System.out.println(user.name); //null,属性(成员变量)具有默认初始化值,可以不赋给定值,声明而使用
System.out.println(user.age); //0
user.talk("日语"); //大家使用日语进行交流
//language = "日语",形参在进行方法调用得时候在进行赋值即可
}
}
class User{
//声明定义在类得一对{}内得变量,叫做成员变量,也叫做类得属性
String name;
int age;
public void talk(String language) { //language:方法形参,局部变量
System.out.println("大家使用 " + language + " 交流");
}
public void love() {
String guNiang = "温柔得南方姑娘"; //guNiang:声明在方法内得变量,局部变量
System.out.println("北方男孩喜欢" + guNiang );
}
}
1.4类中方法得声明和使用:
方法:刻画类当中应该具有得功能(行为)。
比如:Math类:sqrt() - 开方方法 \ random() - 获取随机数得方法
Scanner类:里面所定义得方法主要是用来进行从控制台来获取不同类别的输入得
nextInt()获取int整数型数据方法 next()获取String字符串型数据得方法
Arrays类:数组工具类,用来对数组进行特定操作得具体方法
equals()方法 用来比较两数组是否相等(数组各个位置上得元素都进行对比)
sort(arr)方法 对数组进行排序得方法
举例:人作为一个类具有得一些个方法(功能或者行为)
public void eat(){}
public void sleep(int hour){}
public String getName(){}
public String getNation(String nation){}
方法使用初体验:用心感受吧,骚年:测试用例
/*一、设计类就是设计类的成员
* */
//测试类
public class Person_Test {
public static void main(String[] args) {
//1.创建Person类的对象
Person p = new Person();
//new + 类名,在堆内存中开辟空间,赋随机地址,并创建该抽象类的实例化对象
//2.创建完具体对象以后,就可以直接调用对象的结构(属性 + 方法)了
//调用属性: "对象.属性"
p.name = "Mike";
p.isMarried = true;
System.out.println(p.name); //Mike
System.out.println(p.isMarried); //true
//说明,只要是类创建出来的对象都是引用数据类型,未进行赋值时,就是各个类型的默认初始化
//调用方法:"对象.方法名",只要有了特定的对象实例,就可以进行方法的调用了
p.eat(); //人可以吃饭
p.sleep(); //人可以睡觉
p.talk("中国话"); //人可以说话,用的语言是中国话
//------------------------------->
Person p1 = new Person(); //new + 类名,在对空间重现开辟了一个空间创建了一个对象
//每一个对象都有一个独立的实体,每个对象实体之间的属性和方法互不冲突(都有自己独有的特有的一份对象信息)
System.out.println(p1.name); //Mike?null?报错? 输出:null
System.out.println(p1.isMarried); //false,成员变量未赋值情况下具有默认初始化值
//------------------------->
Person p2 = p;
//引用类型变量之间的赋值操作,是进行首地址的传递,将对象p在堆内存中的首地址赋给p2,那么意味着变量p和变量p2就指向堆内存中相同的对象实体
p2.age = 10;
//那么不管是任何两者之一对这个对象进行的操作,都是同步的,共享的,p2对对象进行修改,那么因为p也指向相同的内存空间,那么接收到的值就是p2修改之后的值
System.out.println(p.age); //10
}
}
class Person{
//1.属性:对应类中的成员变量
String name;
int age;
boolean isMarried;
//2.方法:对应类中的成员方法
public void eat() {
System.out.println("人可以吃饭");
}
public void sleep() {
System.out.println("人可以睡觉");
}
public void talk(String language) {
System.out.println("人可以说话,用的语言是"+ language);
}
}
1.方法得分类:
无返回值 有返回值
无形参 void 方法名(){} 返回值类型 方法名(){}
有形参 void 方法名(形参列表){} 返回值类型 方法名(形参列表){}
2.方法得具体得声明方式:
权限修饰符 (可选关键字) 返回值类型 方法名(形参列表(可有可无,若有可有不止一个形参)){
方法体;
}
注意:可选关键字:static、final、abstract来在指定位置来修饰方法
3.说明:
3.1关于权限修饰符号(由大到小进行排列):
java中规定得4种访问权限修饰符:public、protected、default(默认权限修饰、包访问修饰符)、private
默认权限修饰:在属性和方法前未加任何得访问修饰符号,则该属性和方法就是默认权限修饰符default
3.2返回值类型:有返回值 VS 无返回值
3.2.1如果方法有返回值,则必须在方法声明时,指定返回值得类型(必须返回一个)。同时方法中需要使用return关键字来返回指定类型得数据(变量或者常量),“return 指定数据(变量或者常量)”
如果方法没有返回值,那么使用void来表示没有指定类型得返回值。通常,没有返回值得方法中,就不用使用return了,如果要使用,只能"return;",表示结束此方法得意思
3.3方法名:标识符(java中对于任意可以起名字得地方,都称为标识符),遵循标识符得规则和规范(xxxYyyZzz),要做到见名知意
3.4形参列表:方法可以声明0个,1个,或者多个形参(不可给定特定值,只有在进行具体方法调用得时候,才能传值)。
3.4.1格式:数据类型1 形参1,数据类型2 形参2,...,数据类型n 形参n(各个形参之间用','隔开)
4.return关键字得使用:
1.使用范围:使用在方法体中
2.作用:(1)结束方法
(2)针对于有返回值类型得方法:“return 数据”方法返回方法体执行完毕之后所需得具体得数据(返回值)
3.注意点:return关键字后面不可以声明任何得执行语句(整个方法已然结束,方法得结束就代表方法得出栈操作,方法一旦出栈,就不会再被执行了,呢么定义在return语句后面得语句肯定就不会被执行到了)
5.方法得使用中,可以调用当前类得属性或者方法
特殊得,方法A中又调用了方法A:递归方法
注意:方法中不可以定义方法
方法再体验,骚年,我看你骨骼精奇,看来是看了我得博客,变强了!!!那就再来感受一哈哈方法:
import java.util.Scanner;
public class Method_Test {
public static void main(String[] args) {
Customer cos = new Customer();
int[] arr =new int[] {1,5,7,9,8,6};
cos.sort(arr);
//传入形参,可以让我们对指定传入得数据进行具体得操作,而没有将数据直接写在方法中,
//这样就会限制功能得实现了,例如我们具体得执行得功能就是炒菜功能,形参就相当于调味料,根据炒得不同得菜
//选用不同得调料,而不是在炒菜功能里把调料限制死了,那么我们这个炒菜功能,就只能炒一道菜了
}
}
//客户类
class Customer{
//属性不是重点可以任意定义几个属性
String name;
int age;
boolean isMarried;
//方法
public void eat() {
System.out.println("客户吃饭");
return; //表示结束此方法得意思
//return在方法中一出现,就代表结束当前方法执行了,函数就会出栈,那么return语句之后就不能做任何得操作了
//System.out.println("吃烤山药,两大份得,超好吃");
}
public void sleep(int hour) {
System.out.println("休息了" + hour +"个小时");
}
public String getName() {
return name;
}
public String getNation(String nation) {
String info = "我的国籍是" + nation;
return info;
}
public void sort(int[] arr) {
//...
}
阿道k,难!难!难!难道这就是强者得世界!
不不不!啥也不是!继续看看练习!感受一下方法:
/*定义类Student,包含三个属性:学号number(int),年级state(int),成绩 score(int)。
* 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
* 问题一:打印出3年级(state值为3)的学生信息。
* 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
* */
//测试类
public class Exer4_Test {
public static void main(String[] args) {
//声明Student类型得数组
Student[] s = new Student[20];
for(int i = 0;i < s.length;i++) {
//给数组元素赋值
s[i] = new Student();
//给每一个元素的属性赋值
s[i].number = i + 1;
s[i].state = (int) ((Math.random() * 6 - 1 + 1) + 1);
s[i].score = (int) ((Math.random() * 40 + 1) + 60);
}
//1.打印出3年级(state值为3)的学生信息。
for(int i = 0;i < s.length;i++) {
if(s[i].state == 3) {
System.out.println("学号:" + s[i].number + " 学生成绩: " + s[i].score + " 所在年级: " + s[i].state);
}
}
System.out.println();
//2.使用冒泡排序按学生成绩排序,并遍历所有学生信息
Exer4_Test ex = new Exer4_Test();
ex.bubbleSort(s);
for(int i = 0;i < s.length;i++) {
System.out.println("学号:" + s[i].number + "\t学生成绩: " + s[i].score + "\t所在年级: " + s[i].state);
}
}
//定义具体得冒泡排序得算法
public void bubbleSort(Student[] s) {
for(int i = 0;i < s.length;i++) {
for(int j = 0;j < s.length - 1 -i;j++) {
if(s[j].score > s[j + 1].score) {
//如果需要换序,交换得是元素,元素是Student得对象
Student temp = s[j];
s[j] = s[j + 1];
s[j + 1] = temp;
}
}
}
}
}
//学生类
class Student{
int number; //学号
int state; //年纪
int score; //成绩
}
啊嘞!别溜!还有一个!你最棒了:
/* 3.1 编写程序,声明一个method方法,在方法中打印一个10*8 的*型矩形, 在main方法中调用该方法。
3.2 修改上一个程序,在method方法中,除打印一个10*8的*型矩形外,再 计算该矩形的面积,并将其
作为方法返回值。在main方法中调用该方法, 接收返回的面积值并打印。
3.3 修改上一个程序,在method方法提供m和n两个参数,方法中打印一个 m*n的*型矩形,并计算该矩形
的面积, 将其作为方法返回值。在main方法 中调用该方法,接收返回的面积值并打印。
*/
public class Exer3_Test {
public static void main(String[] args) {
Exer3_Test ex = new Exer3_Test();
//3.1测试
//ex.method();
//3.2测试
//int area = ex.method1();
//System.out.println("长方形得面积为 " + area);
//3.3测试
int area1 = ex.method2(8,6);
System.out.println("长方形得面积为 " + area1);
}
//3.1
// public void method() {
// for(int i = 0;i < 10;i++) {
// for(int j = 0;j < 8;j++) {
// System.out.print("* ");
// }
// System.out.println();
// }
// }
//3.2
// public int method1() {
// for(int i = 0;i < 10;i++) {
// for(int j = 0;j < 8;j++) {
// System.out.print("* ");
// }
// System.out.println();
// }
// return 10 * 8;
// }
//3.3
public int method2(int m,int n) {
for(int i = 0;i < m;i++) {
for(int j = 0;j < n;j++) {
System.out.print("* ");
}
System.out.println();
}
return m * n;
}
}
相信大家对属性和方法都有一个很好得认识了!棒棒哒!
老夫累了,该睡会了,下回再见,拜拜!感兴趣得可以点个关注,持续更新中!!!