JAVABasic
一、计算机基础
1. 计算机组成
2. 进制的概念
2.1二进制的存储
计算机不管是内存还是硬盘,都是以二进制的形式存储。如同一张巨大的表格,里面都是由0和1组成。
- 二进制:逢2进1 基数为2,数值部分用不同的数字,0、1来表示。 (逢2进1便是没有2的概念,遇到2就像前面进一位)比如2,看到2向前进1,2用二进制表示便是10,3是11依此类推
- 十进制:逢十进一基数为10,数值部分用0、1、2、3、4、5、6、7、8、9来表示.
- 十六进制:逢十六进一基数是16,有十六种数字符号,除了在十进制中的0至9外,还另外用6个英文字母A、B、C、D、E、F来表示十进制数的10至15。
2.2二进制的存储(单位)
数据在计算机底层是如何存储的?
- 都是采用二进制:使用0、1按照逢2进1的规则表示数据来存储。
如何快速算出一个数据的二进制形式?
- 除2取余法 6便表示为110
数据在计算机底层存储的最小单位是什么?
- 字节,一个字节等于8个二进制位:1B =8b
二进制转十进制:
2.3关于ASCll编码表
3.java环境搭建
3.1安装java
将给定的安装包安装在电脑上,我们一起去官方网站看看(www.oracle.com/)
我们能看到目前java的版本已经更新到了java17,但是企业中常用的还是java8,原因是因为老的版本,更加稳定,不容易出现错误。我们可以根据实际需求自行选择安装版本。
系统会默认将jdk安装至"C:\Program Files\Java"目录下,(这里最好自己指定目录,目录中不要出现空格以及中文,避免后续产生不必要的麻烦)
接着我们需要配置环境变量,让其能够在任意窗口打开 path环境变量
- 用于记住程序路径,方便在命令行任意路径启动程序
我在最初学习时,也一直没弄懂环境变量是干嘛的,我们以QQ为例,再引入java的环境变量。帮助大家去直观的理解环境变量。
win+r 输入cmd 打开命令行窗口
我们此时输入qq是没有效果的
首先找到QQ程序的执行路径,通常在bin包,发现有qq程序
将这个路径复制
打开环境变量设置
用户变量只针对当前用户 系统变量针对所有用户
点击path
将qq环境变量加进去 点击确定
此时再次在命令行执行qq,你会发现
还是失败!!!
为什么呢?
- 因为我们的环境变量更改之后,原来打开的命令行还没有生效,重新打开命令行工具即可。 此时输入qq,启动成功
接着我们引入正题,配置java环境变量 在最新版本,安装过程中会自动帮助我们配置好环境变量。 但是通常情况下,是需要我们手动添加环境变量
同样的 找到jdk的bin目录,复制路径,添加到环境变量中
图A
配置JAVA_HOME环境变量
复制这个路径
新建环境变量
将最开始图A的那个变量替换,通过%JAVA_HOME% 来固定位置
完成
java
java -version --查看jdk版本
有内容即可。
4.javac 和java的区别
我们编写的java程序都是高级语言,计算机底层是不能够直接识别的,需要通过javac工具的编译才能驱动机器干活。
5.命令行常用命令
6.编写第一个java程序
开发一个java程序,其中要经历三个步骤 编写代码,编译代码,运行代码
下面看一个简单的 Java 程序,它将输出字符串 Hello World
最初学习时,我们可以使用记事本编写代码。这样的好处是,能够更加熟悉Java的一个运行过程,以及对代码的熟练度。
新建一个文件,用记事本的方式打开
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!"); //这句话输出 Helllo world!
}
}
需要注意的是文件名要和类名完全一致,否则会报错。
编写好之后通过在文件所在目录执行 javac HelloWorld.java 进行编译,然后运行
7.java工作原理jdk
7.1.jdk的组成
7.2.java的跨平台,工作原理
- 一次编译,处处可用(核心是因为java公司为不同的平台提供了jvm虚拟机)
## 变量
数据类型
1.自动类型转换机制:
- 类型范围小的变量,可以直接复制给类型范围大的变量
2.我们为什么要进行类型转换?
- 因为在实际编写程序中,会存在不同类型的变量赋值其他类型的变量。
3.什么是自动类型转换?
- 类型范围小的变量,可以直接赋值给类型范围大的变量。
byte 的运算结果会转换为int,需要用int接收
数组
1.数组的基本概念
有一个需求,某某学校招生了,有一百个学生报名,我想记录一下这一百个学生的年龄和姓名,或者计算一下学生的平均年龄,难道我们要定义一百个变量吗?
string a = "杨航"
...
算了不写了。
合理的做法一定是,在内存里找一个片空间,按顺序存起来。其实这个道理很简单,计算机中,我们有这样一种数据结构能帮助我们把想同类型的数据统一聚拢放在一起,他就是【数组】。
2.数组的定义方式
定义:
int[] nums;
初始化:
nums = new int[3];
赋值:
nums[0] = 1;
nums[1] = 4;
nums[2] = 3;
// 直接定义初始化并赋值
int[] nums = {1,2,3};
// 这样写也行
int nums[] = new int[5];
int nums[] = new int[]{1,2,4,5};
// 数组有一个属性,可以获得数组的长度
nums.length
类型[] 名字 = new 类型[长度];
3.数组在计算机中的基本原理
数组在计算机中存储,主要是通过三个步骤
注意:数组变量名中存储的的是数组在内存当中的地址,数组是一种引用数据类型。
总结:
4.数组中的访问
语法:数组名[索引]
System.out.println(ages[0]);
计算数组长度(存放了多少数据) 数组名.length
System.out.println(ages.length);
数组的最大索引:
数组名.length - 1
注意:如果访问数组时,使用的索引超过数组的最大索引,会越界,显示异常
5.数组的遍历
什么是便历:? 所谓便历,就是说一个一个去访问属猪容器中的数据
for (int i = 0; i < ages.length; i++) { }
IDEA中的快捷便历
数组名.fori + 回车 直接生成
一个简单的小案例~
代码实现:
public class LiteralDemo {
public static void main(String[] args) {
//定义一个五个员工的销售额度数组
int[] money = {16,26,366,100};
//定义一个变量,用作最后计算总额
int total = 0;
//分别遍历累加
for (int i = 0; i < money.length; i++) {
total += money[i];
}
//输出
System.out.println(total);
}
}
6.动态初试化数组
先初试化int[] rar = new int[3]
后赋值
rar[0]=1
两种数组定义初始化方式各自适合什么模式?
- 动态初试化:适合开始不确定具体元素值,只知道元素个数的具体场景。
- 静态初试化:明确具体元素值
案例1:
代码实现:
import java.util.Scanner;
public class LiteralDemo {
public static void main(String[] args) {
double[] scores = new double[6];
Scanner sc = new Scanner(System.in);
//遍历数组 输入6个评委的打分
for (int i = 0; i < scores.length; i++) {
System.out.println("请您输入当前第"+(i+1)+"个评委的分数");
scores[i] = sc.nextDouble();
}
double sum = 0;
// 遍历数组中每个元素值进行求和
for (int i = 0; i < scores.length; i++) {
sum +=scores[i];
}
System.out.println("选手最终得分" + (sum / scores.length));
}
7.数组/java程序在计算机中的执行原理
java内存分配介绍
graph TD
方法区 --> 栈内存 -->堆内存
数组在计算机的执行原理
小思考:
8.多个变量指向同一个数组
注意:如果某个数组变量存储的地址是null,那么变量将不再指向任何数组对象。
多个数组变量,指向同一个数组对象的原因,注意事项
- 多个数组中存储的是同一个数组对象中的数据
- 多个变量中修改的都是同一个数组对象中的数据。
9.数组常见案例
数组求最值
代码实现:
public class LiteralDemo {
public static void main(String[] args) {
int[] faceScores = {15,9000,29993,3242,4242,5242,4345,543,534,543,543};
//定义一个最大值
int max = faceScores[0];
for (int i = 0; i < faceScores.length; i++) {
if(faceScores[i] > max) max = faceScores[i];
}
System.out.println("当前妹纸中,颜值得分最高的是" + max +"分");
}
}
数组反转
public class LiteralDemo {
public static void main(String[] args) {
int[] a = {1,2,3,4,5};
//临时变量
int temp;
for (int i = 0,j = a.length-1; i < j; i++,j--) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
}
随机排名
代码实现:
import java.util.Random;
import java.util.Scanner;
public class LiteralDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//初始化数组
int[] codes = new int[5];
//遍历录入
for (int i = 0; i < codes.length; i++) {
System.out.println("请您输入第" + (i+1) + "个工号");
int code = sc.nextInt();
codes[i] = code;
}
Random r = new Random();
//打乱顺序
for (int i = 0; i < codes.length; i++) {
//随机索引
int index = r.nextInt(codes.length);//0 1 2 3 4
//定义临时变量
int temp = codes[index];
codes[index] = codes[i];
codes[i] = temp;
}
for (int i = 0; i < codes.length; i++) {
System.out.print(i+" ");
}
}
}
debug工具的使用-断点调试
方法
1.方法的概念
**方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用。**这句话什么意思呢?意思是,把一段功能代码围在一起,别人都可以来调用它。
方法定义方式
public static int sum(int a,int b){
int c = a+b;
return c;
}
我们看一个需求,比如现在张工、李工两个人都需要求两个整数的和。不使用方法,代码如下。
// 1、李工。
int a = 10;
int b = 20;
int c = a+b;
System.out.println("和是:" + c);
// 2、张工。
int a1 = 10;
int b1 = 20;
int c1 = a1+b1;
System.out.println("和是:" + c1);
阅读上面的代码,我们不难发现。两次求和的代码中,除了求和的数据不一样,代码的组织结构完全一样。
像这种做相同事情的代码,就可以用方法进行封装。需要用到这段代码功能时,让别人调用方法就行。代码如下
//目标:掌握定义方法的完整格式,搞清楚使用方法的好处。
public class MethodDemo1 {
public static void main(String[] args) {
// 需求:假如现在很多程序员都要进行2个整数求和的操作。
// 1、李工。
int rs = sum(10, 20);
System.out.println("和是:" + rs);
// 2、张工。
int rs2 = sum(30, 20);
System.out.println("和是:" + rs2);
}
public static int sum(int a,int b) {
int c = a + b;
return c;
}
}
定义方法的要点
-
方法的修饰符:暂时都使用public static 修饰。(目前看做是固定写法,后面是可以改动的)
-
方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据。
-
形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值。
使用方法的好处
-
提高代码复用性,提升开发效率
-
让程序逻辑更清晰
如下图所示:写好一个方法之后,每一个人都可以直接调用,而不用再重复写相同的代码。所以是提高了代码的复用性,不用写重复代码,自然也提高了开发效率。
2.使用场景
那么让程序的逻辑更加清晰,是如何体现的呢? 比如,我们后期会用所学习的技术,做一个ATM系统,ATM系统中有查看账户、存钱、取钱、修改密码等功能,到时候我们可以把每一个功能都写成一个方法。如下图所示,这样程序的逻辑就更加清晰了。
总结一下
1.什么是方法?
答:方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用
2.方法的完整格式是什么样的?
//格式如下:
修饰符 返回值类型 方法名( 形参列表 ){
方法体代码(需要执行的功能代码)
return 返回值;
}
3.方法要执行必须怎么办?
必须调用才执行;
//调用格式:
方法名(...);
4.使用方法有什么好处?
答:提高代码的复用性,提高开发效率,使程序逻辑更清晰。
3.方法其它形式
实际上设计一个合理的方法,需要重点关注下面两点
- 该方法是否需要接收收据处理
- 方法是否需要返回数据
设计一个合理的方法的原则如下:
- 如果方法不需要返回数据,返回值类型必须申明成void(无返回值申明), 此时方法内部不可以使用return返回数据。
- 方法如果不需要接收外部传递进来的数据,则不需要定义形参,且调用方法时也不可以传数据给方法。
- 没有参数,且没有返回值类型(void)的方法,称为值无参数、无返回值方法。此时调用方法时不能传递数据给方法。
需求1:写一个方法,打印3个"Hello World"
分析:需求已经非常明确,打印的是3个HelloWorld,在方法中直接循环3次就可以完成需求。不需要外部给方法传递数据,所以不需要参数。
需求2:写一个方法,打印若干个"Hello World",具体多少个,由调用者指定
4.方法使用中的常见问题
- 1. 方法在内种没有先后顺序,但是不能把一个方法定义在另一个方法中。
- 2. 方法的返回值类型写void(无返回申明)时,方法内不能使用return返回数据,
如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据。
- 3. return语句的下面,不能编写代码,属于无效的代码,执行不到这儿。
- 4. 方法不调用就不会执行, 调用方法时,传给方法的数据,必须严格匹配方法的参数情况。
- 5. 调用有返回值的方法,有3种方式:
① 可以定义变量接收结果
② 或者直接输出调用,
③ 甚至直接调用;
- 6. 调用无返回值的方法,只有1种方式: 只能直接调用。
5.方法的使用案例
我们知道Java程序的运行,都是在内存中执行的,而内存区域又分为栈、堆和方法区。那Java的方法是在哪个内存区域中执行呢?
答案是栈内存。 每次调用方法,方法都会进栈执行;执行完后,又会弹栈出去。
方法进栈和弹栈的过程,就类似于手枪子弹夹,上子弹和击发子弹的过程。最后上的一颗子弹是,第一个打出来的;第一颗上的子弹,是最后一个打出来的。
总结
1.方法的运行区域在哪里?
答:栈内存。
2.栈有什么特点?方法为什么要在栈中运行自己?
答:先进后出。保证一个方法调用完另一个方法后,可以回来继续执行。
4.java参数的传递机制 (非常重要)
java的传递机制都是:值传递
所谓值传递:指的是在传递实参给方法的形参的时候,传递的是实参变量中存储的值的副本。 同学们肯定想知道,形参是什么?实参又是什么呢? 请看下面这个张图
- 实参:在方法内部定义的量
- 形参:定义方法时,()中所声明的参数
4.1参数传递的基本类型数据
总结:
- 值传递,传输的是实参存储的值副本
4.2参数传递的引用数据类型
我们发现调用change方法时参数是引用类型,实际上也是值传递,只不过参数传递存储的地址值。此时change方法和main方法中两个方法中各自有一个变量arrs,这两个变量记录的是同一个地址值[I@4c873330,change方法把数组中的元素改了,main方法在访问时,元素已经被修改了。
总结一下:
1.基本类型和引用类型的参数在传递的时候有什么不同? - 都是值传递 - 基本类型的参数传递存储的数据值。 - 引用类型的参数传递存储的地址值。
5.方参数传递案例
案例1:
代码:
案例2
代码:
思维:层层拦截,不通过就返回false
6.方法重载
什么是方法重载?
- 方法重载:所谓方法重载指的是:一个类中,出现多个相同的方法名,但是它们的形参列表是不同的,那么这些方法就称为方法重载了。
方法重载的的注意事项:
- 一个类中,只要一些方法的名称相同,形参列表不同,那么他们就是方法的重载了,其它不用管。
- 形参的列表不同指个数、类型、顺序不同,不关心形参
方法重载的应用场景:
一般在开发中,我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很专业的。
比如,我们现在看一个案例
们现在看一个案例
需求:开发武器系统,功能需求如下:
可以默认发一枚武器。
可以指定地区发射一枚武器。
可以指定地区发射多枚武器。
上面的几个需求中,不管以什么样的方式发武器,其实最终的目的都是发武器。
所以我们可以设计几个名称相同的方法,这样调用者调用起来就不用记那么多名字了
public class MethodTest2 {
public static void main(String[] args) {
// 目标:掌握方法重载的应用场景。
fire();
fire("岛国2");
fire("米国", 999);
}
public static void fire(){
fire("岛国");
}
public static void fire(String country){
fire(country, 1);
}
public static void fire(String country, int number){
System.out.println("发射了" + number + "枚武器给" + country);
}
}
总结一下:
1.什么是方法重载?
答:一个类中,多个方法的名称相同,但它们形参列表不同。
2.方法重载需要注意什么?
- 一个类中,只要一些方法的名称相同、形参列表不同,那么它们就是方法重载了,
其它的都不管(如:修饰符,返回值类型是否一样都无所谓)。
- 形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
3、方法重载有啥应用场景?
答:开发中我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很 专业的。
7.return的单独使用
关于方法的定义,我们还剩下最后一种特殊用法,就是在方法中单独使用return语句,可以用来提前结束方法的执行。
如,下面的chu方法中,当除数为0时,就提前结束方法的执行。
public class Test {
public static void main(String[] args) {
System.out.println("开始");
chu(10 , 0);
System.out.println("结束");
}
public static void chu(int a , int b){
if(b == 0){
System.err.println(“您的数据有误!!不执行!!”);
return; // 直接跳出并结束当前chu方法的执行
}
int c = a / b;
System.out.println("除法结果是:"+c);
}
}
第一阶段JAVA编程案例
案例一:买飞机票
我们来分析一下,这个需求该如何实现。将来我们去做一些需求,都是一个一个方法来实现的,所以在这里我们也采用方法来编写。
呢?采用下面的方式来思考
1.首先,考虑方法是否需要接收数据处理?
阅读需求我们会发现,不同月份、不同原价、不同舱位类型优惠方案都不一样;
所以,可以将原价、月份、舱位类型写成参数
2.接着,考虑方法是否有返回值?
阅读需求我们发现,最终结果是求当前用户的优惠票价
所以,可以将优惠票价作为方法的返回值。
3.最后,再考虑方法内部的业务逻辑
先使用if判断月份是旺季还是淡季,然后使用switch分支判断是头等舱还是经济舱,计算 票价
代码如下
public class Test1 {
public static void main(String[] args) {
// 目标:完成买飞机票的案例。
double price = calculate(1000, 11, "头等舱");
System.out.println("优惠价是:" + price);
}
public static double calculate(double price,int month,String type){
// 1、判断当前月份是淡季还是旺季
if(month >= 5 && month <= 10) {
// 旺季
// 2、判断仓位类型。
switch (type){
case "头等舱":
price *= 0.9; // price = price * 0.9;
break;
case "经济舱":
price *= 0.85;
break;
}
}else {
// 淡季
switch (type){
case "头等舱":
price *= 0.7; // price = price * 0.7;
break;
case "经济舱":
price *= 0.65;
break;
}
}
return price;
}
}
案例二:开发验证码
分析:
1.需要传递参数 指定多少位
2.需要一个返回值
3.最后,再考虑方法内部的业务逻辑
1)先按照方法接收的验证码位数n,循环n次
2)每次循环,产生一个字符,可以是数字字符、或者大小写字母字符
3)定义一个String类型的变量用于记住产生的每位随机字符
public class Test2 {
public static void main(String[] args) {
// 目标:完成生成随机验证码。
System.out.println(createCode(8));
}
public static String createCode(int n){
//1)先按照方法接收的验证码位数n,循环n次
Random r = new Random();
//3)定义一个String类型的变量用于记住产生的每位随机字符
String code = "";
for (int i = 1; i <= n; i++) {
// i = 1 2 3 4 5
//2)每次循环,产生一个字符,可以是数字字符、或者大小写字母字符
// 思路:随机一个0 1 2之间的数字出来,0代表随机一个数字字符,1、2代表随机大写字母,小写字母。
r
switch (type) {
case 0:
// 随机一个数字字符
code += r.nextInt(10); // 0 - 9 code = code + 8
break;
case 1:
// 随机一个大写字符 A 65 Z 65+25 (0 - 25) + 65
char ch1 = (char) (r.nextInt(26) + 65);
code += ch1;
break;
case 2:
// 随机一个小写字符 a 97 z 97+25 (0 - 25) + 97
char ch2 = (char) (r.nextInt(26) + 97);
code += ch2;
break;
}
}
return code;
}
}
案例三:评委打分
1.首先,考虑方法是否需要接收数据来处理?
需求中说,有多个评委的打分,但是到底多少个评委呢? 可以由调用者传递
所以,我们可以把评委的个数写成参数;
2.接着,考虑方法是否需要有返回值?
需求中,想要的最终结果是平均分
所以,返回值就是平均分;
3.最后,再考虑方法内部的业务逻辑
1)假设评委的个位为n个,那么就需要n个评委的分数,首先可以新建一个长度为n的数组, 用来存储每一个评委的分数
2)循环n次,使用Scanner键盘录入n个1~100范围内的整数,并把整数存储到数组中
3)求数组中元素的总和、最大值、最小值
4)最后再计算平均值; 平均值 = (和-最大值-最小值)/(数组.length-2);
代码如下:
public class Test3 {
public static void main(String[] args) {
// 目标:完成评委打分案例。
System.out.println("当前选手得分是:" + getAverageScore(6));
}
public static double getAverageScore(int n){
// 1、定义一个动态初始化的数组,负责后期存入评委的打分
int[] scores = new int[n]; // 6
// scores = [0, 0, 0, 0, 0, 0]
// 2、遍历数组的每个位置,依次录入评委的分数
Scanner sc = new Scanner(System.in);
for (int i = 0; i < scores.length; i++) {
// i = 0 1 2 3 4 5
System.out.println("请您录入第"+ (i + 1) +"个评委的分数:");
int score = sc.nextInt();
scores[i] = score;
}
// 3、从数组中计算出总分,找出最高分,最低分。
int sum = 0; // 求总分用的变量
int max = scores[0]; // 求最大值的
int min = scores[0]; // 求最小值的。
// 遍历数组找出这些数据的。
for (int i = 0; i < scores.length; i++) {
// i = 0 1 2 3 4 5
int score = scores[i];
// 求和
sum += score;
// 求最大值
if(score > max){
max = score;
}
// 求最小值
if(score < min){
min = score;
}
}
// 4、计算出平均分并返回
return 1.0 * (sum - min - max) / (number - 2);
}
}
案例四:数字加密
代码实现:
public class Test4 {
public static void main(String[] args) {
// 目标:完成数字加密程序的开发。
System.out.println("加密后的结果是:" + encrypt(8346));
}
public static String encrypt(int number){
// number = 198
// 1、把这个密码拆分成一个一个的数字,才可以对其进行加密啊。
int[] numbers = split(number);
// numbers = [1, 9, 8, 3]
// 2、遍历这个数组中的每个数字,对其进行加密处理。
for (int i = 0; i < numbers.length; i++) {
// i = 0 1 2 3
numbers[i] = (numbers[i] + 5) % 10;
}
// numbers = [6, 4, 3, 8]
// 3、对数组反转,把对数组进行反转的操作交给一个独立的方法来完成
reverse(numbers);
// numbers = [8, 3, 4, 6]
// 4、把这些加密的数字拼接起来做为加密后的结果返回即可。
String data = "";
for (int i = 0; i < numbers.length; i++) {
data += numbers[i];
}
return data;
}
public static void reverse(int[] numbers) {
// 反转数组的
// numbers = [6, 4, 3, 8]
// i j
for (int i = 0, j = numbers.length - 1; i < j; i++,j--) {
// 交换i和j位置处的值。
// 1、把后一个位置处的值交给一个临时变量先存起来
int temp = numbers[j];
// 2、把前一个位置处的值赋值给后一个位置处
numbers[j] = numbers[i];
// 3、把后一个位置处原来的值(由临时变量记住着)赋值给前一个位置
numbers[i] = temp;
}
}
public static int[] split(int number) {
// number = 1983
int[] numbers = new int[4];
numbers[0] = number / 1000;
numbers[1] = (number / 100) % 10;
numbers[2] = (number / 10) % 10;
numbers[3] = number % 10;
return numbers;
}
}
面向对象基础
1.面向对象入门
学习完前面的课程后,说明Java的基础语法就全掌握了。
接下来,我们要学习的是Java中最核心的课程——面向对象编程。
那这种编程套路是咋回事呢? 接下来,我们通过一个案例快速的认识一下。
现在假设我们需要处理的是学生的姓名、语文成绩、数学成绩这三个数据,要求打印输出这个学生的总成绩,和平均成绩。
所谓编写对象编程,就是把要处理的数据交给对象,让对象来处理。
2.深刻理解面向对象
2.1面向对象有什么好处
Java的祖师爷,詹姆斯高斯林认为,在这个世界中 **万物皆对象!**任何一个对象都可以包含一些数据,数据属于哪个对象,就由哪个对象来处理。
有了对象,我们就可以把数据交给对象来进行处理。
所以面向对象编程的好处,用一句话总结就是:面向对象的开发更符合人类的思维习惯,让编程变得更加简单、更加直观。
2.2面向对象是什么
对象实际上是一种特殊的数据结构
你可以把对象,理解成一张表格,表格中所记录的数据,就是对象拥有的数据。
2.3 对象是如何出来的
刚刚我们讲到对象就是一张数据表,那么这个数据表是怎么来的呢?这张表是不会无缘无故存在的,因为Java也不知道你这个对象要处理哪些数据,所以这张表需要我们设计出来。
而设计这张的表的角色,就是类。类可以理解成对象的设计图
一句话总结:对象可以理解成一张数据表,而数据表中可以有哪些数据,是有类来设计的。
3.对象的执行原理
按照我们之前讲的数组的执行原理,数组变量记录的其实数数组在堆内存中的地址。其实面向对象的代码执行原理和数组的执行原理是非常类似的。
其实Student s1 = new Student();这句话中的原理如下
-
Student s1表示的是在栈内存中,创建了一个Student类型的变量,变量名为s1 -
而
new Student()会在堆内存中创建一个对象,而对象中包含学生的属性名和属性值同时系统会为这个Student对象分配一个地址值0x4f3f5b24
-
接着把对象的地址赋值给栈内存中的变量s1,通过s1记录的地址就可以找到这个对象
-
当执行
s1.name=“播妞”时,其实就是通过s1找到对象的地址,再通过对象找到对象的name属性,再给对象的name属性赋值为播妞;
搞明白Student s1 = new Student();的原理之后,Student s2 = new Student();原理完全一样,只是在堆内存中重新创建了一个对象,又有一个新的地址。s2.name是访问另对象的属性。
4.类和对象的一些注意事项
第一条:一个代码文件中,可以写多个class类,但是只能有一个是public修饰,且public修饰的类必须和文件名相同。
假设文件名为Demo1.java,这个文件中假设有两个类Demo1类和Student类,代码如下
//public修饰的类Demo1,和文件名Demo1相同
public class Demo1{
}
class Student{
}
**第二条:**对象与对象之间的数据不会相互影响,但是多个变量指向同一个对象会相互影响。
如下图所示,s1和s2两个变量分别记录的是两个对象的地址值,各自修改各自属性值,是互不影响的。
如下图所示,s1和s2两个变量记录的是同一个对象的地址值,s1修改对象的属性值,再用s2访问这个属性,会发现已经被修改了。
5.this关键词的含义
this是什么呢?this实际上就是一个变量,可以用在方法中,拿到当前类的对象。
我们看下图所示代码,通过代码来体会这句话到底是什么意思。哪一个对象调用方法方法中的this就是哪一个对象
运行结果:
this有什么用呢?
通过this在方法中可以访问本类对象的成员变量。我们看下图代码,分析打印结果是多少
关于this关键字我们就学习到这里,重点记住这句话:哪一个对象调用方法方法中的this就是哪一个对象
6.构造器
关于构造器,我们掌握下面几个问题就可以了:
- 什么是构造器?
- 掌握构造器的特点?
- 构造器的应用场景?
- 构造器有哪些注意事项?
我们一个问题一个问题的来学习,先来学习什么是构造器?
-
什么是构造器?
构造器其实是一种特殊的方法,但是这个方法没有返回值类型,方法名必须和类名相同。
如下图所示:下面有一个Student类,构造器名称也必须叫Student;也有空参数构造器,也可以有有参数构造器。
- 构造器的特点
在创建对象时,会调用构造器。
也就是说 new Student()就是在执行构造器,当构造器执行完了,也就意味着对象创建成功。
当执行new Student("播仔",99)创建对象时,就是在执行有参数构造器,当有参数构造器执行完,就意味着对象创建完毕了。
,我们记住一句话:new 对象就是在执行构造方法
构造器的应用场景?
其实构造器就是用来创建对象的。可以在创建对象时给对象的属性做一些初始化操作。如下图所示:
-
构造器的注意事项?
学习完构造器的应用场景之后,接下来我们再看一下构造器有哪些注意事项。
1.在设计一个类时,如果不写构造器,Java会自动生成一个无参数构造器。 2.一定定义了有参数构造器,Java就不再提供空参数构造器,此时建议自己加一个无参数构造器。
关于构造器的这几个问题我们再总结一下。掌握这几个问题,构造方法就算完全明白了。
1.什么是构造器?
答:构造器其实是一种特殊的方法,但是这个方法没有返回值类型,方法名必须和类名相 同。
2.构造器什么时候执行?
答:new 对象就是在执行构造方法;
3.构造方法的应用场景是什么?
答:在创建对象时,可以用构造方法给成员变量赋值
4.构造方法有哪些注意事项?
1)在设计一个类时,如果不写构造器,Java会自动生成一个无参数构造器。
2)一定定义了有参数构造器,Java就不再提供空参数构造器,此时建议自己加一个无参数构 造器。
7、封装性
各位同学,接下来我们再学习一个面向对象很重要的特征叫做——封装性。
7.1什么是封装呢?
所谓封装,就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理数据的方法,都设计到一个对象中去。
比如:在设计学生类时,把学生对象的姓名、语文成绩、数学成绩三个属性,以及求学生总分、平均分的方法,都封装到学生对象中来。
现在我们已经知道什么是封装了。那我们学习封装,学习个啥呢? 其实在实际开发中,在用类设计对事处理的数据,以及对数据处理的方法时,是有一些设计规范的。
封装的设计规范用8个字总结,就是:合理隐藏、合理暴露
比如,设计一辆汽车时,汽车的发动机、变速箱等一些零件并不需要让每一个开车的知道,所以就把它们隐藏到了汽车的内部。
把发动机、变速箱等这些零件隐藏起来,这样做其实更加安全,因为并不是所有人都很懂发动机、变速箱,如果暴露在外面很可能会被不懂的人弄坏。
在设计汽车时,除了隐藏部分零件,但是还是得合理的暴露一些东西出来,让司机能够操纵汽车,让汽车跑起来。比如:点火按钮啊、方向盘啊、刹车啊、油门啊、档把啊... 这些就是故意暴露出来让司机操纵汽车的。
好了,到现在我们已经理解什么是封装的一些规范了。就是:合理暴露、合理隐藏.
7.2. 封装在代码中的体现
知道什么是封装之后,那封装在代码中如何体现呢?一般我们在设计一个类时,会将成员变量隐藏,然后把操作成员变量的方法对外暴露。
这里需要用到一个修饰符,叫private,被private修饰的变量或者方法,只能在本类中被访问。
如下图所示,private double score; 就相当于把score变量封装在了Student对象的内部,且不对外暴露,你想要在其他类中访问score这个变量就,就不能直接访问了;
如果你想给Student对象的score属性赋值,得调用对外暴露的方法setScore(int score),在这个方法中可以对调用者传递过来的数据进行一些控制,更加安全。
当你想获取socre变量的值时,就得调用对外暴露的另一个方法 getScore()
关于封装我们就学习到这里了。
8、实体JavaBean
接下来,我们学习一个面向对象编程中,经常写的一种类——叫实体JavaBean类。我们先来看什么是实体类?
1. 什么是实体类?
实体类就是一种特殊的类,它需要满足下面的要求:
接下来我们按照要求,写一个Student实体类;
写完实体类之后,我们看一看它有什么特点? 其实我们会发现实体类中除了有给对象存、取值的方法就没有提供其他方法了。所以实体类仅仅只是用来封装数据用的。
知道实体类有什么特点之后,接着我们看一下它有哪些应用场景?
2. 实体类的应用场景
在实际开发中,实体类仅仅只用来封装数据,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离。如下图所示

在实际应用中,会将类作为一种数据类型使用。如下图所示,在StudentOperator类中,定义一个Student类型的成员变量student,然后使用构造器给student成员变量赋值。
然后在Student的printPass()方法中,使用student调用Student对象的方法,对Student对象的数据进行处理。
到这里,我们已经学习了JavaBean实体类的是什么,以及它的应用场景,我们总结一下
1.JavaBean实体类是什么?有啥特点
JavaBean实体类,是一种特殊的;它需要私有化成员变量,有空参数构造方法、同时提供 getXxx和setXxx方法;
JavaBean实体类仅仅只用来封装数据,只提供对数据进行存和取的方法
2.JavaBean的应用场景?
JavaBean实体类,只负责封装数据,而把数据处理的操作放在其他类中,以实现数据和数 据处理相分离。
9.面向对象综合实例
按照下面的步骤来完成需求
1. 第一步:定义电影类
首先每一部电影,都包含这部电影的相关信息,比如:电影的编号(id)、电影的名称(name)、电影的价格(price)、电影的分数(score)、电影的导演(director)、电影的主演(actor)、电影的简介(info)。
为了去描述每一部电影,有哪些信息,我们可以设计一个电影类(Movie),电影类仅仅只是为了封装电影的信息,所以按照JavaBean类的标准写法来写就行。
public class Movie {
private int id;
private String name;
private double price;
private double score;
private String director;
private String actor;
private String info;
public Movie() {
}
public Movie(int id, String name, double price, double score, String director, String actor, String info) {
this.id = id;
this.name = name;
this.price = price;
this.score = score;
this.director = director;
this.actor = actor;
this.info = info;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getDirector() {
return director;
}
public void setDirector(String director) {
this.director = director;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
2. 第二步:定义电影操作类
前面我们定义的Movie类,仅仅只是用来封装每一部电影的信息。为了让电影数据和电影数据的操作相分离,我们还得有一个电影操作类(MovieOperator)。
因为系统中有多部电影,所以电影操作类中MovieOperator,需要有一个Movie[] movies; 用来存储多部电影对象;
同时在MovieOperator类中,提供对外提供,对电影数组进行操作的方法。如printAllMovies()用于打印数组中所有的电影信息,searchMovieById(int id)方法根据id查找一个电影的信息并打印。
public class MovieOperator {
//因为系统中有多部电影,所以电影操作类中,需要有一个Movie的数组
private Movie[] movies;
public MovieOperator(Movie[] movies){
this.movies = movies;q
}
/** 1、展示系统全部电影信息 movies = [m1, m2, m3, ...]*/
public void printAllMovies(){
System.out.println("-----系统全部电影信息如下:-------");
for (int i = 0; i < movies.length; i++) {
Movie m = movies[i];
System.out.println("编号:" + m.getId());
System.out.println("名称:" + m.getName());
System.out.println("价格:" + m.getPrice());
System.out.println("------------------------");
}
}
public void searchMovieById(int id){
for (int i = 0; i < movies.length; i++) {
Movie m = movies[i];
if(m.getId() == id){
System.out.println("该电影详情如下:");
System.out.println("编号:" + m.getId());
System.out.println("名称:" + m.getName());
System.out.println("价格:" + m.getPrice());
System.out.println("得分:" + m.getScore());
System.out.println("导演:" + m.getDirector());
System.out.println("主演:" + m.getActor());
System.out.println("其他信息:" + m.getInfo());
return; // 已经找到了电影信息,没有必要再执行了
}
}
System.out.println("没有该电影信息~");
}
}
3. 第三步:定义测试类
最后,我们需要在测试类中,准备好所有的电影数据,并用一个数组保存起来。每一部电影的数据可以封装成一个对象。然后把对象用数组存起来即可。
public class Test {
public static void main(String[] args) {
//创建一个Movie类型的数组
Movie[] movies = new Movie[4];
//创建4个电影对象,分别存储到movies数组中
movies[0] = new Movie(1,"水门桥", 38.9, 9.8, "徐克", "吴京","12万人想看");
movies[1] = new Movie(2, "出拳吧", 39, 7.8, "唐晓白", "田雨","3.5万人想看");
movies[2] = new Movie(3,"月球陨落", 42, 7.9, "罗兰", "贝瑞","17.9万人想看");
movies[3] = new Movie(4,"一点就到家", 35, 8.7, "许宏宇", "刘昊然","10.8万人想看");
}
}
准备好测试数据之后,接下来就需要对电影数据进行操作。我们已经把对电影操作先关的功能写到了MovieOperator类中,所以接下来,创建MovieOperator类对象,调用方法就可以完成相关功能。
继续再main方法中,接着写下面的代码。
// 4、创建一个电影操作类的对象,接收电影数据,并对其进行业务处理
MovieOperator operator = new MovieOperator(movies);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("==电影信息系统==");
System.out.println("1、查询全部电影信息");
System.out.println("2、根据id查询某个电影的详细信息展示");
System.out.println("请您输入操作命令:");
int command = sc.nextInt();
switch (command) {
case 1:
// 展示全部电影信息
operator.printAllMovies();
break;
case 2:
// 根据id查询某个电影的详细信息展示
System.out.println("请您输入查询的电影id:");
int id = sc.nextInt();
operator.searchMovieById(id);
break;
default:
System.out.println("您输入的命令有问题~~");
}
}
到这里,电影信息系统就完成了。 小伙伴们,自己尝试写一下吧!!
10、成员变量和局部变量的区别
各位同学,面向对象的基础内容咱们已经学习完了。同学们在面向对象代码时,经常会把成员变量和局部变量搞混。所以现在我们讲一讲他们的区别。
如下图所示,成员变量在类中方法外,而局部变量在方法中。
到这里,我们关于面向对象的基础知识就学习完了。面向对象的核心点就是封装,将数据和数据的处理方式,都封装到对象中; 至于对象要封装哪些数据?对数据进行怎样的处理? 需要通过类来设计。