最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

JAVA学习笔记_基础篇01

来源:博客园

第一章:了解(chapter)

复习方法: 找到视频 每个章节 结合笔记。

https://www.bilibili.com/video/BV1fh411y7R8?p=266&spm_id_from=pageDriver&vd_source=5c60787a1cdddc0e6d23d53b2b6bb1c4

第一阶段:建立编程思想(包括:基本语法、数组、排序和查找、面向对象编程、零钱通、房屋出租系统、迷宫、八皇后、汉诺塔 )

第二阶段:提升编程能力(包括: 枚举和注解、Exception、常用类、集合、泛型、线程、IO流、坦克大战)


(资料图片)

第三阶段: 增强分析需求,代码实现能力(包括: 网络编程、反射、Mysql、JDBC和连接池、正则表达式、Java8 Java11 新特性、马踏棋盘、满汉楼、多用户通信系统)

如何快速学习Java新技术.(重点!!)

步骤1:需求步骤2:解决方法步骤3:引出新技术和知识点步骤5:快速入门:(基本的程序:CRUD)先进行增删改查
工作需求 跳槽 技术控1. 能否使用旧技术.能解决,但不完美\解决不了,新技术有是什么优势.步骤4: 学习新技术和知识点的基本原理和基本语法(不要考虑细节.)先会用再考虑血肉.步骤6:开始考虑研究技术细节\注意事项\使用规范\如何优化. 优化永无止境. 这个才是拉开差距的地方.每个人看到的点不一样.

第一小节: 1~3

1. JAVA就业方向

  1. JavaEE软件工程师

    • 电商\团购\众筹\sns\教育\金融
  2. 大数据软件工程师

    • 应用\算法\分析和挖掘
  3. Android软件工程师

    • 安卓软件工程师

2.JAVA开发场景-ssm android hadoop(大数据) 程序员角度

  1. Spring(轻量级的容器框架)
  2. SpringMVC(分层的web开发框架)
  3. MyBatis(持久性框架)
  4. android(安卓)
  5. hadoop(大数据)

3.应用方面

  1. 企业级应用

    • 软件系统\各类型网站\金融\电信\交通\电子商务等.
  2. Android平台应用

    • 安卓电视\app
  3. 移动(嵌入式开发)领域:

    • 嵌入式开发 pos机\汽车通讯设备\机顶盒\大屏幕投影娱乐设备等.

4.程序是什么

程序是: 计算机执行某些操作或解决某些问题而编写的一系列有序指令的集合.

编程上 输入->计算->输出这样的步骤.

计算机上, 编程文件->javac 讲java文件转录成class文件 ->再运行class文件,才能实现.

第二小节:

JVM的主要组成部分及其作用有哪些 - 编程语言 - 亿速云 (yisu.com) 细看这部分

1.java 概述

  1. java8和java11 是LTS 公共版本

    java8 23-可扩展到30-年

    java11 23-可扩展到26-年

  2. java95年第一个版本,GOSLING(gosling)为创始人

  3. javaSE(标准版)JAVAEE(企业版)\JAVAME(移动终端和编程.)没用了已经

2.java特点

  1. Java是面向对象的(oop)

  2. java是健壮的.强类型机制 \异常处理 \垃圾自动回收等是其健壮性的重要保障

  3. java语言是跨平台性的.(主要因为JVM)

    ​Test.java文件编译成Test.class文件. 这个class文件可以在Windows和Linux操作系统下运行.这就是跨平台性.​根本原因是JVM.不同操作系统,使用不一样的JVM.

  4. java语言是解释型语言.

    • 解释性语言:javascript\PHP\java
    • 编译性语言:c\c++

区别:

​解释性语言: 编译后的代码,不能直接被机器执行,需要解释器来执行,( javac )(就是转化为class文件).

​编译性语言:可以直接被机器执行.

所以难怪 性能差一些.

3.java运行机制及运行过程

  • java核心机制\java虚拟机[JVM java virtual machine]

    • 基本介绍:

      1.)JVM 是一个虚拟的计算机,具有指令集并使用不用的存储区域. 负责执行指令 \管理数据 \内存 \寄存器\都包含在JDK**中

      2.)对于不同的平台,有不同的虚拟机.

      3.)java虚拟机机制屏蔽了地城运行平台的差别,实现了"一次编译,到处运行"

运行过程 :

​集成开发工具写的java文件 通过javac(编译器编译)成class文件(字节码文件) 然后加载到jvm中 先加载类装载器(装载类和静态类等) 然后开始运行程序

java文件通过编译器变成了.class文件,接下来类加载器又将这些.class文件加载到JVM中。 其实可以一句话来解释:类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。 

最后由解释器

4.什么是JDK\JRE

JDK:

  • JDK全称(Java Development kit) java开发工具包
    • JDK= JRE + java的开发工具 (java,javac,javadoc,javap等)
  • JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE,所以安装了JDK就不用单独安装JRE了.

JRE:

  • JRE(Java Runtime Environment) java 运行环境
    • JRE= JVM +java的核心类库[类]
  • 包括Java虚拟机(JVM java virtual Machine)和java 程序所需的核心类库
  • 需要运行JAVA程序 就只要安装JRE就可以了,因为已经编译过了."

JDK = JRE + java开发工具

JRE = JVM + 核心类库

jre 就是jvm + 核心类库 保障java程序运行

jdk 在jre的基础上添加了开发工具 java javac javadoc javap等等

5.JDK 安装

公共JRE eclipse有时候要使用公共JRE. 可以不安装.

环境变量的作用,是为了在dos的任何目录都能使用java和javac

环境变量界面有两个

一个是用户变量

一个用系统变量

分别有不同的作用域

仅当前用户

和使用该电脑的所有用户

第三小节:

1.java入门.

第一个java文件. 打印 "Hello,World".

源文件字节码文件结果
先编写 .java文件javac编译 成 .class 文件运行 类 结果

运行问题:, 中文编码报错.

因为cmd控制台使用的GBK格式,右键cmd控制台查看控制台的属性

需要更改为GBK格式 才能使用,也可以使用GB18030,

2.java的格式问题

  1. 源文件 必须是 java为拓展名

  2. main方法有固定格式不能更改

    ​public static void main(String[] args){}

  3. 严格区分大小写\分号";"结尾\大括号成对出现

  4. 一个源文件中有且只有一个public类,文件名也需要按这个类名命名.其他类个数不限,

    可以将main写在非public类中,然后指定运行非public类,入口方法就是非public的main方法了.

一个java文件有多个类,编译后,没一个类 都会生成一个.class文件.

每个非public类中都可以使用主方法,因为生成的独立的class文件, 只要调用对应的类的class文件.

第四小节

1.转义字符

Tab键在DOS可以自动补全。

\t == table 制表符

"\r" 回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;

"\n" 换行,换到当前位置的下一行,而不会回到行首

Unix系统里,每行结尾只有“<换行>”,即"\n";Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”,即"\r";。

​一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

// \t:制表位\实现对齐的功能.  空四个字节.System.out.println("北京\t深圳\t上海");// \n: 换行符System.out.println("jack\nsmith\nmary");// \\: 一个\System.out.println("\\t"+"\n双斜杠"+"\\\\t");// \": 一个"// \": 一个"//跳过// \r:一个回车 //1. 会先输出黄烘南,\r后面的字 会替换掉前面的黄烘南三个字System.out.println("黄烘南\r好");//好烘南 //回车加换行.System.out.println("黄烘南\r\n好好学习");//黄烘南//好好学习//练习System.out.println("书名\t作者\t价格\t销量\n三国\t罗贯中\t120\t1000");//书名    作者    价格    销量//三国    罗贯中  120     1000

2.容易产生的错误

1与l

0和o

中英文符号问题

拼写错误

非法字符错误问题

3.注释(comment)

做好注释.

多行快捷键是ctrl +shift+/ 单行快捷键是ctrl+/

多行注释不可以在嵌套多行注释.

单行\多行\文档

//单行注释 comment/*多行注释多行快捷键是ctrl +shift+/  单行快捷键是ctrl+/多行注释不可以在嵌套多行注释.*/

文档注释:

注释内容可以被JDK提供的工具 javadoc所解析,生成一套网页文件形式体现的程序说明文档,一般写在类的前面

了解基本格式\如何生成\实例

/** * @author hhn * @version 1.0 *  * */public class Hello{//编写一个主方法 程序入口public static void main(String[] args){//输出System.out.println("黄烘南 is studying java ");}}

javadoc附录:

标签描述示例
@author标识一个类的作者,一般用于类注释@author description
@deprecated指名一个过期的类或成员,表明该类或方法不建议使用@deprecated description
指明当前文档根目录的路径Directory Path
@exception可能抛出异常的说明,一般用于方法注释@exception exception-name explanation
从直接父类继承的注释Inherits a comment from the immediate surperclass.
插入一个到另一个主题的链接
插入一个到另一个主题的链接,但是该链接显示纯文本字体Inserts an in-line link to another topic.
@param说明一个方法的参数,一般用于方法注释@param parameter-name explanation
@return说明返回值类型,一般用于方法注释,不能出现再构造方法中@return explanation
@see指定一个到另一个主题的链接@see anchor
@serial说明一个序列化属性@serial description
@serialData说明通过 writeObject() 和 writeExternal() 方法写的数据@serialData description
@serialField说明一个 ObjectStreamField 组件@serialField name type description
@since说明从哪个版本起开始有了这个函数@since release
@throws和 @exception 标签一样.The @throws tag has the same meaning as the @exception tag.
显示常量的值,该常量必须是 static 属性。Displays the value of a constant, which must be a static field.
@version指定类的版本,一般用于类注释@version info

4.java代码规范

  1. 类、方法的注释,要以javadoc的方式来写

  2. 非java Doc的注释,往往是给代码的维护者观看,如何修改等问题

  3. 使用tab操作,实现缩进,默认整体向右移动,使用shift+tab整体左移

  4. 运算符和 = 两边习惯性各加一个空格比如: int = 1 + 1; 要每个都分开

  5. 源文件使用utf-8编码

  6. 行宽不超过80一行不超过80

  7. 代码编写次行风格行尾风格.

次行: 每次进行大括号都进行换行

行尾: 大括号在行尾.

5.DOS命令

DOS原理:

指令--->发送给DOS系统, (1.接受指令,2.解析指令,3.执行指令.)--->最终体现在windows操作系统中

颜色:

·命令:color f0  帮助:color ?  作用:改变背景及字体颜色·命令:cls  作用:清屏

目录

·命令:dir  作用:浏览当前文件夹的内容(带标识的为文件夹,否则为文件)  其他用法:  dir 指定路径  dir d:\  dir d:\pic  dir /a #浏览所有内容,包括隐藏内容·命令:盘符:  作用:切换分区, 如:c: d: e:·命令:cd ..  作用:退出一级目录·命令:cd 文件夹名  作用:进入文件夹·Tab键:补全路径功能·命令:cd \  作用:直接退到根目录命令: tree 加目录名作用:生成子级目录树·路径:  相对路径:针对当前路径有效,如:  ..\456  绝对路径:从根开始写路径,如:  \123\345  ·注释:  fsutil fsinfo drives #可以查看当前系统的分区列表

文件操作:

·命令:md 文件夹 [文件夹 文件夹 ....]·命令:rd 文件夹 [文件夹 文件夹 ....]  作用:删除空文件夹  命令:rd 文件夹 /s/q          (/s是递归删除,/q是无提示删除)  作用:无提示递归删除非空文件夹·创建文件方法:  echo 字符串 >>[路径\]文件名.扩展名  注释:>>和>都可以将命令的输出内容输入到某文件中,若文件不存在,则同时创建该文件  ·>>为追加  ·>为覆盖  ·>nul为不显示回显  ·2>为错误信息输出并覆盖  ·2>>为错误信息输出并追加  ·2>nul 经典用法:屏幕上不要有任何的报错  如:rd . /s/q 2>nul·显示文件内容命令:  type 文件名.扩展名  作用:浏览一个文件的内容·命令:del 文件名.扩展名  作用:删除文件  ·del *.txt #删除所有txt结尾的文件  ·del *.* #删除所有文件  ·del *.* /s /q #无提示删除所有文件  注释:*为通配符,代表任意字符,任意长度        ?为单字符匹配·ren 原名 新名 #重命名,可以重命名文件和文件夹。·命令:copy [路径\]源文件全名 目标路径[\新文件全名]  作用:复制文件·命令:move [路径\]源文件全名 目标路径[\新文件全名]  作用:移动文件

6.相对\绝对路径

相对路径:

从当前目录开始定位,形成的一个路径.

只有单个目录

"java快速学习\javacode"

从顶层开始定位,形成的路径.

"C:\Users\qianl\Desktop\java快速学习\javacode"

例子:

从当前目录访问另一个目录的文件.

相对路径:

"cd ..\..\abc2\test200\hello.txt"

绝对路径:

"cd d:"

"\abc2\test200\hello.txt"

第二章:变量

第一小节:

1.字符串拼接

57   是一个常量"57"   是一个字符串常量(5和7这两个字符的序列)

计算时:

System.out.println("57 + 32 = " + (57 + 32));

1.先计算小括号,再由于是字符串 + 数字 (或者数字 + 字符串)都会将 数字 变成 字符串. 最终拼和成"57 + 32 = 89".

如果不加括号,则会变成: 字符串 + 57 然后 字符串 + 32 .变成"57 + 32 = 5732"

如果计算放在前面,那么就没有关系. 因为从左往右进行.

2.变量的声明

变量三大要素:

类型+名称+值

int x = 1; 声明和赋值 (声明加初始化 也是初始值)

int类型 名为x的盒子 盒子里的值为 1;

integer 整数

3.数据类型

类型名称关键字占用内存取值范围
字节型byte1 字节-128~127
短整型short2 字节-32768~32767
整型int4 字节-2147483648~2147483647
长整型long8 字节-9223372036854775808L~9223372036854775807L
单精度浮点型float4 字节+/-3.4E+38F(6~7 个有效位)
双精度浮点型double8 字节+/-1.8E+308 (15 个有效位)
字符型char2 字节ISO 单一字符集
布尔型boolean1 字节true 或 false

1.整数类型

long类型需要注意加 "l" 或者: "L" 通常大写

int x = 1; int只有8个字节int x = 1L;  long有16个字节,范围超了.int x = (int)(1L);

2.浮点类型

默认是double类型

浮点数 = 符号位 + 指数位 + 尾数位.

因为小数,精度丢失 (所以都是近似值)

**d也可以使用d为结尾 ** 可加可不加 小数默认是double

即: double d1 = 3d; //ok的 d1 = 3.0

float f = 1.1f;   4个字节double d = 1.1;  8个字节    //如果是0开头的小数可以省略    double d1 = 0.123    double d2 = .123    //也可以使用科学计数法    5.12e2 //512.0    5.12e-2 // 0.0512  使用陷阱:就是分数问题.    double num1 = 2.7;double num2 = 8.1/3; // 计算是2.7 输出的是 2.69999999997    num2 是一个接近2.7的小数,是近似值.               原因是 8.1这个数被转变为二进制的时候,最小二倍数法,取得的小数是很长的,超过了double的精度,所以这个数被截断了,除于3的时候就变成了一个不足2.7的数了.

​原因是 8.1这个数被转变为二进制的时候,最小二倍数法,取得的小数是很长的,超过了double的精度,所以这个数被截断了,除于3的时候就变成了一个不足2.7的数了. 之后再用乘二取余法

应该以两个数的差值的绝对值,在某个进度范围内进行判断.

Math.abs()获取绝对值

使用Math类的方法

3.char类型

单个字符使用char 长字符串使用String类

char 单引号, String使用双引号 这里的String是"类" 首字母大写才是类

char的本质是"ISO 单一字符集"; 也就是一串数字

char类型也是可以计算的,本质是数字,所以计算的结果也是一串数字对应的字符

存储:

比如:"a"是97 会转换成二进制(110 0001),然后进行存储.

char c1 = "a";char c2 = "黄"; char c3 = "\t"; //表示制表符的四个空格char c4 = 97;  //表示ISO单一字符集System.out.println(c1);System.out.println(c2);System.out.println(c3);System.out.println(c4);a黄a

只有英文字符,不用汉字就不用那么多个字符了.

注意,utf-8 是一个可变长的所以不是所有汉字都是3个字节(1到6个字节)

4.boolean类型

注意点: java中不能使用0或者非0整数来替代true和false python 非强制性语言可以 默认是False

boolean bool = true;if (bool == true) {System.out.println("考试通过了,恭喜");}else {System.out.println("下次努力");}

4.二进制

byte是一个8位的数,

第一个是符号位,后面为实际存储

十进制转二进制:

最小二倍数法

首位为符号位, 指数位+尾数位, 进行科学计数法以后,小数点浮点,所以叫浮点数. 通过补码来进行数据还原.

取出来的叫原码 要转化为反码 反码+1 变补码 然后java都是补码进行计算的

二进制转十进制:

乘2取余法

乘2 整数位大于1舍去,取余数

5.java8 在线API

https://www.matools.com/api/java8

按包——》找类——》找方法。也可以直接检索

API的结构 :注意 每个包内 接口,类,异常有很多个。

java基础包    java.applet         Applet所需的类和接口    java.awt            图形用户界面所需的类和接口    java.beans          Java bean所需的类和接口  ♥ java.io             系统输入/输出所需的类和接口  ♥ java.lang           Java语言编程的基础类和接口    java.math           支持任意精度整数和任意精度小数的类和接口(与lang下的math类更专业)  ♥ java.net            网络应用的类和接口    java.nio            定义缓冲区,它们是数据容器,并提供其他NIO包的概述    java.rmi            远程调用(RMI)的类和接口    java.security       用于安全框架的类和接口  ♥ java.sql            访问和处理数据源中数据的类和接口    java.text           支持按与语言无关方式处理文本、数据、数字和消息的类和接口    java.time          日期,时间,瞬间和持续时间的主要API  ♥ java.util           集合框架、事件模型、日期和时间机制、国际化等的类和接口   java扩展包等    javax.accessibility    定义用户界面组件与提供对这些组件的访问的辅助技术之间的合同    javax.activity     包含ORB机械在解组时抛出的活动服务相关异常    javax.annotation.processing  用于声明注释处理器和允许注释处理器与注释处理工具环境通信的设施    javax.crypto        提供加密操作的类和接口    javax.imageio       Java Image I / O API的主要包………    javax.rmi           支持RMI-IIOP的类和接口    javax.serverlet     支持serverlet编程的类和接口    javax.sound         支持音频设备数字接口(MIDI)的类和接口    javax.swing         扩充和增强基本图形用户界面功能的类和接口    javax.transaction   包含有几个关于事务上下文异常的类     org.omg.CORBA       支持OMG CORBA API到Java语言映射的类和接口     等等

6.类型转换

小范围转变成大范围能自动转型,大变小需要强制转换.

小类能自动继承大类的方法, 但是大类没有小类的方法.

1.自动转换:

精度小的类型自动转换为精度大的数据类型,这就是自动转换 精度(容积)

auto == automatic (自动化)

表示自动化的意思

注意事项:

所以没声明具体类型的数字 默认为 int类型

  1. 多类型数据混合计算,自动转换为容量最大的类型,然后计算
  2. byte, short 和char之间不能互相自动转换
  3. byte ,short和char之间可以计算,会先转换为int类型, 因为char算是数字 (int类型).
  4. boolean不参与转换.
  5. 表达式结果,自动提升为操作数中最大的类型.

2.强制类型转换

基本方法:

int x = (int)(1L);需要的值类型 = (需要的值类型)(被转换的类型);

两种可能:

1.精度缺失,

没有四舍五入 int等整型 直接去除小数点后的数

2.数据溢出

不再声明的范围内的数 溢出

细节说明:

主要是char和int变量之间,需要强制转换,.

我的结果:

正确结果:

注意:

1.第一和第二题, 9和11 都默认为int类型,计算取最高的类型.

2.第三题,计算全部转换成了最高的float类型 可以自动转换给double.

3.第四题, byte和short进行计算会自动变成int类型 这时候 就不能再自动转给byte short 和char了

3.String类型转换成基本数据类型

基本数据类型转String ,加双引号

String转基本数据类型, 需要使用包装类

每一个数据类型都有一个包装类,也就是将基本数据类型变成对应的"类"

parse 解析

基础类型与对应包装类编写区别

除了int Integer

char Character

其他都是首字母大写

String转换char类型,

使用 String.charAt( index ) 方法,返回在index位置的char字符。(返回值:char )使用 String.toCharArray( ) 方法,将String 转化为 字符串数组。(返回值:char[] )

也可以转换成字符串数组

char转换成String类型

//1.效率最高得到一种方法 String s = String.valueOf("c");//2.将字符串数组转化为字符串String s = String.valueOf(new char[] {"G","e","o","o","o"});//3.用 Character 的 toString(char) 方法  ==>  实际上还是调用了String.valueOf(char)String s = Character.toString("c");//4.new 一个 Character 调用 toString()String s = new Character("c").toString();//5.直接用 空 String 拼接 "c"String s = "" + "c" ;//第5种方法效率最低,因为String类是 final 属性// "" + "c" 时候需要创建新的 String 类 ,如果进行很多次拼接则要创建很多个类虚拟机栈可能会溢出

注意事项:

  1. String的数据是非数字的时候,转换成整数的话,就会抛出异常.程序会中止.那么捕获和处理方法需要写出.

7.键盘输入规范

注意点:

1.导入包 import java.util.Scanner;

2.固定格式: Scanner stdIn = new Scanner(System.in);

3.不能以 Scanner为类名, 会重写Scanner方法.

4.限制输入的数据类型 ,靠next+类型 来限制.

//注意导入类(文本扫描)import java.util.Scanner;public class Inport{public static void main(String[] args) {// 固定格式Scanner stdIn = new Scanner(System.in);System.out.println("请输入要计算的值");System.out.println("x:");int x = stdIn.nextInt();System.out.println("y:");int y = stdIn.nextInt();System.out.println("x + y = " + (x + y));System.out.println("x - y = " + (x - y));System.out.println("x * y = " + (x * y));System.out.println("x / y = " + (x / y));}}

8.生成随机数(Random)

也可以使用Math方法进行,注意看API的 Random的方法

//注意导入类 随机数类import java.util.Random;public class Random01{public static void main(String[] args) {// 固定格式Random Rand = new Random();int lucky = Rand.nextInt(10); //0~9的随机数.System.out.println("今天的幸运数字是:" + lucky + ".");// 1. 1~9的随机数// 2. -9~-1的随机数// 3. 10~99的随机数int one = 1;int num = Rand.nextInt(10); //1~9的随机数.System.out.println("今天的幸运数字是:" + (num + one) + ".");int num1 = Rand.nextInt(9);//0到 8System.out.println("今天的负数是:" + (-(num1 + one)) + "."); //- (1到9)int num2 = Rand.nextInt(90);// 0到89System.out.println("今天的正数是:" + (num2 + 10) + ".");//+10 变成10-99}}
//Math.Random 是生成随机数,会生成一个 double类型的数 [0.0,1.0)//任务,一直生成1到100的数
for (; ; ) {//加1才能成为1到100 i = (int)(Math.random()*100) + 1;System.out.println(i); j++;if (i == 97){System.out.println(i + "次数" + j);break;}

第三章:运算符

1.算术运算符

加减乘除 求余 自增自减(按照顺序进行计算.)

有两个操作数的也叫二元运算符

除法计算问题:

记住一个问题:

计算以最高精度的数为准,整数默认int 小数默认double

所以下面的 10 / 4 = 2 10.0 / 4 = 2.5

取模问题:

取模有一个公式:

本质:m % n = m - (int)(m / n) * n

注意:余值结果符号和 m (被模数) 符号有关,m为负数则余值为负数,m为正数则余值为正数。 同时注意,(m/n的结果 是会被化为int类型的)

自加问题:

注意 :

int j = 8;

int k = j++; //取值后运算.

以后输出的k = 8, j = 9;

原理:

使用了中间数 temp 来进行临存储 值

替换成 j与k

int j = 1;k = j++;// temp = j;  k = temp;  j = j + 1; //  1     1  结果  k = 1      j = 2//这样更符合 先赋值,后运算.int j = 1;k = ++j;//  j = j + 1;  temp = j; k = temp;//   j=2     temp = 2    k = 2//这样更符合 先赋值,后运算.

1.先赋值后计算:

i = 10; i1 = 11; i2 = 20

2.先计算后赋值

i2 = 19 ; i = i2 = 19; i1 = 11 ;

除法计算:

由于5/9 都是默认int类型,得到的小于1 所以直接舍去小数位,变成0 后面什么都是0

更改方法:

改为5.0以后, 因为计算变成全部都是double类型, 所以变成了有小数位的,得到的结果也就有小数了.

2. 关系运算符

结果都是boolean类型 ,只有true和false两种结果

通常在if的判断语句中使用

= (表示赋值)

== 表示比较

hsp 是不是String类中的对象

3.逻辑运算符

分组学习:

短路 && || !

短路:

​判断条件时 , 判断第一个条件就可能可以得到结果, 作用与& 和 | 相同,右边的情况将不再执行. && 的时候 左边为false 则短路 (只要有一个是假 就整个是假)

|| 的时候 左边为true 则短路 (只要有一个真 就整个是真)

如下: 短路&& 由于a<1 不成立,后面的代码将不再执行 也就是右边的++b不再执行. ↑

输出为: 4 和 9

逻辑 & | ^

^ 异或表示结果不同

例题1:

例题2:

4.赋值运算符

就是 计算的同时赋值.

1.注意 只能是变量,同时 左边只能是变量, 效果等价正常加减乘除. 因为也是计算,所以会类型转换(注意是,强制类型转换! ) byte b = 2; b += 3 ; 也就是 b = (byte)(b+3);

5.三元运算符

三元运算符,可以替代简单的 if 判断计算.

注意: 最后的a和b结果是 结果后 会重新赋值与变动,

6.运算符优先级

只有单目运算和赋值运算,才会从右向左进行. 慢慢熟悉

7.标识符规则

规则是强制

规范是公约但不强制

标识符: 就是所以可以自己命名字符的 就叫标识符

主要:

  1. 不能使用关键字和goto 这个保留字, 不能数字开头 注意大小写,

中间不能有空格!!

标识符规范:

  • 类: 开头大写 驼峰

  • finial : 全大写中间 _ 连接

  • 方法,变量 totalNum 驼峰

8.进制问题

二进制:

0b 0B

八进制 0开头

十六进制 0x 或者 0X

二进制转十进制

八进制转十进制

十六进制转十进制

十进制转二进制

最小二倍数法倒取余数

一个字节是8位 前面补0

就是0010 0010

十进制转八进制

十进制转十六进制

二进制转八进制 十六进制

原因: 2的三次方就是8 正好8进制

二进制转十六进制

原因 : 2的四次方就是16 正好16进制

八进制转二进制

十六进制转换位二进制

9.位运算 位移运算(原码\反码\补码) & | ^ ~

//>>> 叫无符号位移  没有<<<符号

相当于除2和乘2 低位溢出 << 2 这个2相当于 2的次方

例子:

重点:

1.正数包括0 其反码 补码 都是他本身

2.负数的反码是符号位除外取反, 补码是 反码+1

3.计算机全部使用的是补码的形式进行的

4.运算结果要看原码(也就是需要进行补码的还原)

位运算规则

例子:

2&3的运算:

重点: int类型 是4个字节的 一共 32位

计算是补码的计算,

结果是原码!

负数的取反运算

(~-2)

整数的取反

(~2)

第五章:程序控制结构 (开始理解编程思想)

1.顺序控制

程序从上到下逐行执行,中间没有任何判断和跳转

注意事项: 声明和使用的顺序 不能错误

例子如下:

2.分支控制( if else switch)

让程序有选择的执行,分支控制有:

1.单分支

基本语法:

单分支

if(条件表达式){执行代码块; (判断为 true时执行,否则跳过)}如果只有一条语句代码块 , 可以不用{}, 到那时还是建议使用    

单分支流程图:

2.双分支

基本语法:

示意:

Scanner stdIn = new Scanner(System.in);System.out.println("请输入年龄");int age = stdIn.nextInt();if(age>18){System.out.println("送进监狱");}else {System.out.println("送进管教所");}

双分支流程图:

3.多分支

基本语法:

注意: 1)多分支中 可以没有else语句, 如果所有条件都是false 则一个执行入口都没有.

  1. 如果有else,所有表达式都是false 则执行else的代码块

多分支流程图:

嵌套分支:

例题:

先进行是否决赛的判断 所以获取成绩,只有成绩达标了 才获取性别

注意字符串变字符类型:

练习:

价格 money        获取月份        获取年龄 if(month 为 旺季){        if (18 < age){            票价 money/2        }else if( 18<= age && age <=60){            票价 money        }else{            money/3        }}else{    if ( 18<= age && age <=60 ){        票价 = 40    }else {        票价 = 20    }    }

4.switch分支结构

swutch的结构:

由switch和 case语句块组成

switch流程图:

注意一点: 没有break语句的 跳出switch的话, 就会直接执行语句块2 不会进行判断 也就是

穿透switch.

例子:

注意格式,还有输入值与判断值的类型对应

//固定格式:Scanner stdIn = new Scanner(System.in);System.out.println("请输入a-g");char day = stdIn.next().charAt(0);switch(day){case "a":System.out.println("今天星期一");break;case "b":System.out.println("今天星期二");break;case "c":System.out.println("今天星期三");break;case "d":System.out.println("今天星期四");break;case "e":System.out.println("今天星期五");break;case "f":System.out.println("今天星期六");break;case "g":System.out.println("今天星期日");break;default:System.out.println("无效字符");break;}

switch 分支细节:

1.类型一致或能自动转换,

2.返回值必须是固定类型()

3,必须是常量,不能是变量

4,default是可选的

5.没有break会产生 switch穿透.

例题:

灵活思路

表达式是可以计算和转换的,转换成可以使用的返回值类型:

switch嵌套在if中

使用穿透switch:

就是条件合并,345 只显示一条输出语句

如下;

if和switch的比较:

switch 适合 值比较小 且符合6个类型的情况

if则是进行范围判断.

3.循环控制( for while dowhile 多重循环(双循环))

1.for循环控制

基本语法:

注意四要素.

for循环流程图:

先进行循环变量的初始化,然后判断循环条件, 真则执行语句, 执行完成再进行循环变量的迭代

例题: 打印十次"Hello,world"

for(int i = 1;i <= 10;i++){// 1 到 10次 输出完 不满足条件就跳出.    System.out.println("Hello,World");}

for循环的细节:

1.条件判断必须是Boolean值

2.初始化可以写for 外面 然后只用一个变量名来引用 迭代可以写执行语句后面. 执行顺序一样. 注意还是要 加 ";" 如果条件也进行省略 那就会死循环

如图:

3, 注意初始化的多个需要类型一致,逗号分隔(格式) 迭代也能多条语句

4, 输出结果为: 00,12,24

for循环重点例题:

打印1~100之间所以9的倍数,并统计个数,计算总和.

public class For01{public static void main(String[] args) {int sumNum = 0;int j = 0;int start = 1;int end = 100;    //将初始值和条件 变成 可以赋值的变量, 从解决个案问题 变成解决共性问题int number = 9;for(int i = start; i <= end; i++){if(i % number == 0){sumNum += i;j += 1;System.out.println("9的倍数:" + i );}}System.out.println("个数:" + j);System.out.println("和:" + sumNum);}}

编程思想问题:

2.while循环控制

基本语法:

while循环控制流程图:

执行条件,进行循环体, 迭代

操作和迭代放一起了

例子:

3.do..while

do..while 是至少循环一次.

基本语法. 先执行 后判断,

执行流程图:

例题1:

例题2: 就是先打一顿再说

4.多重循环控制

就是循环的嵌套, for循环的嵌套 ,一般不要超过2次

分析: i可以取 0 1 j 可以 取 0 1 2 所以总次数是 2*3 一共6次

打印九九乘法表:

for(int i = 1;i <= 9;i++){for(int j = 1 ;j <= i;j++){System.out.print(j + "x" + i + "=" + i*j + "\t"); //print 不换行,+\t 排版}System.out.println(""); //打印完一轮开始换行}

打印空心金字塔:

//打印*金字塔   1 3 5 7 9 个星  空格 星 与行数的关系for(int i = 1;i <= 5; i++){for(int k = 1;k <= (5-i);k++){                 // 这里的0 需要注意,要和i互动System.out.print(" ");}for (int j = 1;j <= (2*i-1); j++) {            //这里也是 需要与i互动System.out.print("*");}System.out.println("");}

打印空心金字塔

//可以将i=5 替换成变量,获得一个想多大就多大的空心金字塔//打印空心*金字塔   1 3 5 7 9 个星  空格 星 与行数的关系for(int i = 1;i <= 5; i++){for(int k = 1;k <= (5-i);k++){                 // 这里的0 需要注意,要和i互动System.out.print(" ");}for (int j = 1;j <= (2*i-1); j++) {            //这里也是 需要与i互动/*if(i == 5){System.out.print("*");}else if (j == 1  || j == (2*i-1)) {  //使得第一个星和最后一个星正常打印,同时排除最后一层金字塔System.out.print("*");}else{System.out.print(" ");}*/if (j == 1  || j == (2*i-1) || i == 5) {  //使得第一个星和最后一个星正常打印,同时排除最后一层金字塔System.out.print("*");}else{System.out.print(" ");}}System.out.println("");}

4.循环终止,跳过,退出break 和 continue 和return

1.break:终止语句块的执行

流程图:

例题:

//Math.Random 是生成随机数,会生成一个 double类型的数 [0.0,1.0)//任务,一直生成1到100的数

循环跳出

//Math.Random 是生成随机数,会生成一个 double类型的数 [0.0,1.0)//任务,一直生成1到100的数int i = 0; //收集随机数int j = 0;//收集次数for (; ; ) {System.out.println((int)(Math.random()*100) + 1); //加1才能成为1到100 i = (int)(Math.random()*100);j++;if (i == 97){System.out.println(i + "次数" + j);break;}}

注意事项:

可以通过标签语句来指定嵌套语句中的那一层语句块

没有写break 默认退出最近的(break所在的循环)

在1-100以内的数求和, 求出当和 第一次大于20的当前数

int sum = 0;int num = 20;int i = 1;  //作用域扩大了for(;i <= 100; i++){    sum += i;//累积    if(sum > num){        System.out.println("和>20时候 当前数i+" + i);        break;    }}System.out.println("当前数=" + i);//当前数

重点:equals比较

避免空指针, 就是name的值可能是null的 然后避免null去调用方法

2.continue (持续)

基本语法:

注意: 跳过本次执行,开始下次循环

流程图:

继续下一次循环

例题:

也可以使用标签 (也就是goto)

3.return

1.return关键字并不是专门用于跳出循环的,return的功能是结束一个方法。 一旦在循环体内执行到一个return语句,return语句将会结束该方法,循环自然也随之结束。与continue和break不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。

章节综合练习题:

题目1: break

注意: while的使用方法, 她可以直接使用true来进行无限循环

public static void main(String[] args) {double money = 100000;int number = 0;while(true){if (money > 50000) {money *= 0.95;number++;}else if (money >= 1000) {money -= 1000;number++;}else{break;}}System.out.println("剩下多少钱" + money + "次数" + number);}

求水仙花数

System.out.println(number1 + "次数" + number2);*/int number1 = 0;//水仙花数int number2 = 0;//非水仙花数for(int d = 100;d < 1000;d++){int d1=d % 10;int d2 =d / 10 % 10;int d3 =d / 100 % 10;if((d1 * d1 * d1 + d2 * d2 * d2 + d3 * d3 * d3) == d){System.out.println(d);number1++;}else{number2++;}}System.out.println(number1 + "次数" + number2);

循环加双判断, 更加简洁. if里嵌套if的方法

//每行输出5个1-100之间不能被5整除的数int num = 0;for(int d = 1;d < 100;d++){if((d % 5 != 0 )){num++;System.out.print(d+"\t"); if ( num % 5 == 0 ) {System.out.println();}}}

问题:听懂和会做: 做题会、项目不会

首先,二者并不是等价的,只有知识,没有实践。

缺乏练习过程

听懂教练的话,不去使用器械,并不会长肌肉。

思想与业务逻辑要联系、

我亦无他,唯手熟尔。

第六章:数组的重要性(array 数组)引用类型

使用现有的知识去考虑,设置单个变量去记录每个数组的数,再进行计算。

数组,则是一个变量去处理一串同类型的数。

//数组类型  数组名 数据   0到5 就是六个数double[] hens = {3,5,1,3.4,2,50};//可以遍历double total = 0;for(int i = 0; i < hens.length; i++){    //下标访问数组    total +=hens[i];}System.out.println(total + "平均" + total/6);

1.数组的使用

1.数组初始化

1.动态初始化 1.

一共做了两步:

声明和创建数组一起.

数据类型 数据名[] = new 数据类型[大小] ;    //这是为了给c/c++程序员的写法。//java中还是放在前面// 数据类型[] 数据名 = new 数据类型[大小];dataType[] arrayRefVar = new dataType[arraySize];

2.动态初始化 2.

//第二种://先声明 再赋值.double[] a; //还没使用内部空间,只是一个空值, a = new double[10];// new了以后才开辟空间 一共10个 8个字节的数据.

3.静态初始化.

// 第二种方法: 直接赋值.dataType[] arrayRefVar = {value0, value1, ..., valuek};

2.数组的注意事项

1,数组是相同类型.

2.数组中元素可以是所有类型 ,基础类型和引用类型,但只能一种.

3.创建后,没有赋值会有默认值.

  • int\short\byte\long\ 都是0

  • false\double 0.0

float\double 0.0

  • char \u0000

  • boolean false

  • String null

3.使用数组的步骤 : 1.声明数组\开辟空间. 2. 给数组的元素进行赋值 3. 使用数组

4.数组下标从0开始.

5.使用范围必须在下标范围内 否则越界异常

6.数组属于引用类型,数组型数据是对象(object). 就是数组的本质是个对象.

3.数组练习

1,创建一个char类型的26个元素的数组,分明放置"A"-"Z".使用for循环访问所以元素并打印出来.

//1,创建一个char类型的26个元素的数组,分明放置"A"-"Z".使用for循环访问所以元素并打印出来.//1 先查找A的对应数字是多少. char a = "A";System.out.println((int)a); // 65// 创建可以容纳26个字母的数组char[] array1 = new char[26];//赋值与打印数组//方法一:for(int i = 0;i < array1.length; i++){array1[i] = (char)(65+i);System.out.println(array1[i]);}//方法二:int i = 0;for(char element: array1){element = (char)(65+i);i++;System.out.println(element);}

2.请写出一个数组int[] 的最大值{4,-1,9,23,10},并得到对应的下标.

//2.请写出一个数组int[] 的最大值{4,-1,9,10,23},并得到对应的下标.//比较大小  需要一个中间值来进行int[] intArray = {3,-1,9,23,10};int sum = 0;   //sum = intArray[0]; 假设第一个数就是最大值int subscript = 0;System.out.println(intArray.length);//5for(int i = 0; i < intArray.length; i++ ){  // int i = 1; 这样可以直接从第二个数开始比较if(sum < intArray[i]){sum = intArray[i];subscript = i;}}System.out.println("最大值"+sum + "下标为"+subscript);

4.数组赋值机制 (assign 分配)

1.基本数据类型的赋值,这个值指的是具体的数据,而且互相互不影响.

//数值拷贝int n1 =2; int n2 = n1; //这个时候 n1 = 2  ,  n2 = 2;

2.数组在默认情况下,是引用传递, 赋的值是地址, 会影响原有的值

//assign(分配)int[] arr1 = {1,2,3};int[] arr2 = arr1;arr2[0] = 10;for(int element:arr1){    System.out.println(element);} 1023

值传递(值拷贝) 和 引用传递 的区别

值传递 (值拷贝)

引用传递

指向的是同一个空间

5.数组拷贝

使用Array方法进行拷贝,或者方法进行拷贝;

//数组拷贝  创建数组2成为同样长度的数组int[] arr1 = {10,20,30};int[] arr2 = new int[arr1.length];int x = 0;for(int i1:arr1){arr2[x] = i1;x++;}//测试拷贝是否成功,修改数组2arr2[0] = 19;//打印数组1for(int i1:arr1){System.out.println(i1);}// 10 20 30//打印数组2for(int i2:arr2){System.out.println(i2);}// 19 20 30 

6.数组反转

同一数组反转.

注意循环次数 除于2

长度从1开始的 所以长度作为下标时 需要减1

//数组反转int[] arr = {11,22,33,44,55,66};//反转数组 使用中间变量//使用变量int reverse = 0;for(int i = 0;i < arr.length/2; i++){ //因为是同时替换两端的数,所以只要进行一半。 3.reverse = arr[i];arr[i] = arr[arr.length-1-i];arr[arr.length-1-i] = reverse;}for (int i:arr ) {System.out.println(i);}

使用逆序赋值

注意: 第一 arr 逆序取值,赋值给arr2 (正向取值)    取值为下标时 长度-1    最后进行数组赋值,指向同一个地址.    arr原有的指向空间会被指定为垃圾, jvm空间不足时进行销毁

7.数组扩容

动态添加元素,

数组扩容 需要一个中间数组.

//数组扩容   int[] arr = {1,2,3};   int[] arr1 = new int[arr.length + 1];   int reverse = 0;   for(int i = 0;i < arr.length; i++){    arr1[i] = arr[i];   }   arr1[arr1.length-1] = 4;   arr = arr1;   for (int i:arr ) {   System.out.println(i);   }

数组扩容 用户决定是否继续添加 也可以使用do while

//数组扩容 用户决定是否继续添加Scanner stdIn = new Scanner(System.in);int[] arr = new int[0];for(;;){System.out.println("请问是否继续添加值 y/n");char result = stdIn.next().charAt(0);if(result == "y"){System.out.println("请问输入要增加的数字");int number = stdIn.nextInt();int[] arr1 = new int[arr.length + 1];int reverse = 0;for(int i = 0;i < arr.length; i++){ arr1[i] = arr[i];}arr1[arr1.length-1] = number;arr = arr1;for (int i:arr ) {System.out.println(i);}}else{System.out.println("程序结束");break;}}for (int i:arr ) {System.out.println(i);}

2.排序

1.冒泡排序法:

五个元素 24,69,80,57,13

使数组成为从小到大的有序数列.

冒泡排序: 时间复杂度n^2

//冒泡排序 需要交换,就需要一个中介.//需要注意的就是 判断条件  (1.循环结束,2.if判断条件)int[] BubbleSort = {24,69,80,57,13};int num = 0;for(int i = 0;i < BubbleSort.length-1; i++){ //次数 进行4次就可以了for(int j = 1; j < BubbleSort.length-i; j++){ // 小于(长度-i)  因为第一次就会筛出最大的一个 //有问题肯定是判断出问题   if(BubbleSort[j-1] > BubbleSort[j]){num = BubbleSort[j-1];BubbleSort[j-1] = BubbleSort[j];BubbleSort[j] = num;}}}for(int i = 0; i < BubbleSort.length; i++){System.out.println(BubbleSort[i]);}

2.冒泡排序优化:

使用标识,减少第一个循环

//冒泡排序 需要交换,就需要一个中介.//需要注意的就是 判断条件  (1.循环结束,2.if判断条件)int[] BubbleSort = {24,69,80,57,13};int num = 0;System.out.println(BubbleSort.length);for(int i = 0;i < BubbleSort.length-1; i++){ //次数 进行4次  只需要4次就可以int flag = 1;//每次循环重新初始化for(int j = 1; j < BubbleSort.length-i; j++){ // 小于(长度-i)  因为第一次就会筛出最大的一个 //有问题肯定是判断出问题   if(BubbleSort[j-1] > BubbleSort[j]){num = BubbleSort[j-1];BubbleSort[j-1] = BubbleSort[j];BubbleSort[j] = num;flag = 0;//标记发生了交换}}//运行完for第二个循环 就会进来判断 没有交换 就说明排序完成if(flag == 1){return;}}for(int i = 0; i < BubbleSort.length; i++){System.out.println(BubbleSort[i]);}

冒泡排序优化: 因为内循环的后面几位已经比较完成了 所以不用进行再次比较

记录下最后交换的下标 来赋值给内循环结束时间.

//冒泡排序 需要交换,就需要一个中介.//需要注意的就是 判断条件  (1.循环结束,2.if判断条件)int[] BubbleSort = {24,69,80,57,13};int num = 0;int tempPostion = 0;int len = BubbleSort.length-1;//记录内循环条件for(int i = 0;i < BubbleSort.length-1; i++){ //次数 进行4次  只需要4次就可以int flag = 1;//每次循环重新初始化for(int j = 0; j < len-i ; j++){ // 小于(长度-i)  因为第一次就会筛出最大的一个 //有问题肯定是判断出问题   if(BubbleSort[j] > BubbleSort[j+1]){num = BubbleSort[j];BubbleSort[j] = BubbleSort[j+1];BubbleSort[j+1] = num;flag = 0;//标记发生了交换tempPostion = j;}}//运行完for第二个循环 就会进来判断 没有交换 就说明排序完成len = tempPostion;if(flag == 1){return;}}for(int i = 0; i < BubbleSort.length; i++){System.out.println(BubbleSort[i]);}

冒泡算法

package Array;/** * @Auther: qianl * @Date: 2022/10/18 01:18 * @Description: */public class MyTools {    public static void main(String[] args) {        int[] arr = {1,2,41,43,213,45,312,451,225,3};        int temp = 0;        for (int i = 0; i < arr.length - 1; i++) {            for (int j = 0; j < arr.length - 1 - i; j++) {                if(arr[j] > arr[j + 1]){                    temp = arr[j];                    arr[j] = arr[j + 1];                    arr[j + 1] = temp;                }            }        }        for (int k:arr             ) {            System.out.println(k);        }    }}

3.查找

查找方法:

1.顺序查找:

注意使用equals的判断, 需要注意空值引用方法的问题.

String[] names = {"山顶巨人","雪山狮王","种花家传人"};Scanner stdIn = new Scanner(System.in);System.out.println("请输入你要寻找的名字");String findName = stdIn.next();int index = -1;for (int i = 0; i < names.length; i++ ) {if(findName.equals(names[i])) {System.out.println("找到了"+names[i]+"下标是"+i);index = i;break;}}if(index == -1){System.out.println("寻找失败");}

2.二分查找:

4.数组插入数据

练习:已知一个升序的数组,要求插入一个元素,该数组顺序依旧是升序,比如:

[10,12,45,90] 添加23后,数组为[10,12,23,45,90]

int[] arr = {10,12,45,90};int[] arrNew = new int[arr.length + 1];int number = 111;for (int i=0; i < arr.length ; i++ ) {if(arr[i] > number){ //判断开始进行替换for (int j=i+1;j

韩顺平的 ,思路更清晰

//标记的方法int[] arr = {10,12,45,90};int[] arrNew = new int[arr.length + 1];int index = -1;int number = 23;for (int i = 0; i < arr.length ; i++ ) {if(arr[i] >= number){ //判断开始进行替换index = i;break;}}////最后一种情况if(index == -1){index = arr.length;}for (int i = 0,j = 0; i < arrNew.length ; i++ ) {if(i != index){arrNew[i] = arr[j];  //只要没有index 就没事发生, 不然就j会比i少1 就能使得arrNew多一个下标j++;} else {arrNew[i] = number;}}arr = arrNew;for(int element:arr){System.out.println(element);}

5.多维数组(二维) dimensional(纬度的)

二维数组.TwoDimansionalArray.

1.二维数组的使用

//声明与开辟空间同时int[][] arr = new int[10][20];//也可以先声明 再开辟空间int[][] arr;arr = new int[10][10];//直接赋值int[][] arr ={{0,0,0,0,0,0},{0,0,1,0,0,0},{0,2,0,3,0,0},{0,0,0,0,0,0}};

也可以这样声明:

//TwoDimansionalArray 二维数组int[][] arr ={{0,0,0,0,0,0},{0,0,1,0,0,0},{0,2,0,3,0,0},{0,0,0,0,0,0}};for (int i = 0;i < arr.length; i++ ) {for (int j = 0;j < arr[i].length ; j++ ) {System.out.print(arr[i][j] + " ");}System.out.println();}

2.内存布局 (数组的本质就是对象,引用地址)

3.列数不一致

要求:

代码:

//打印/*122333*/int[][] arr = new int[3][];//只有地址没开空间 结合地址//还没有开数组空间for (int i = 0;i 

4.两种遍历方式

都是取一维数组 然后遍历每一个一维数组的数据

for(int[] i:arr){for (int j:i) {System.out.print(j);}System.out.println();}for (int i = 0; i 

5.打印杨辉三角

注意: 分清楚初始和头尾的情况. 然后再进行上层数的相加

//打印杨辉三角/*111121133114641...*/int[][] arr = new int[10][];for (int i = 0;i < arr.length;i++ ) {arr[i] = new int[i+1]; //每一行数组 都是一个多长的数组.for (int j = 0; j < arr[i].length ;j++ ) {if(i==0 || i == 1){arr[i][j] = 1;// 第一第二行都是1continue;}else if(j == 0 || j == (arr[i].length-1) ){arr[i][j] = 1; // 第三行开始,头尾是1}else{arr[i][j] = arr[i-1][j-1] + arr[i-1][j]; // 其他三角的中间部分,是上一行的 前一个数与当前数的和}}}for(int[] i:arr){for (int j:i) {System.out.print(j+" ");}System.out.println();}

第七章:类与对象

1.类的概念

类 : 一类事物

对象: 同一类中 不同对象(实例)

类是抽象概念,是一个事物的共公属性,对象是一个实例 是类的一个具体个体.

2.类的内存布局 java中只有值传递没有引用传递!

参考网站:https://blog.csdn.net/scf1198862746/article/details/102681799?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-102681799-blog-105889845.pc_relevant_multi_platform_whitelistv3&spm=1001.2101.3001.4242.2&utm_relevant_index=4

字符串内存分配:

对于字符串,其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

如以下代码:

String s1 = "china";    String s2 = "china";    String s3 = "china";     String ss1 = new String("china");    String ss2 = new String("china");    String ss3 = new String("china");

这里解释一下黄色这3个箭头,对于通过new产生一个字符串(假设为“china”)时,会先去常量池中查找是否已经有了“china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。

总结:

**字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。 **

基本类型内存分配:

对于基础类型的变量和常量,变量和引用存储在栈中,常量存储在常量池中。类(对象)\数组\接口存在堆中

如以下代码:

int i1 = 9;    int i2 = 9;    int i3 = 9;     final int INT1 = 9;    final int INT2 = 9;    final int INT3 = 9;

编译器先处理int i1 = 9;首先它会在栈中创建一个变量为i1的引用,然后查找栈中是否有9这个值,如果没找到,就将9存放进来,然后将i1指向9。接着处理int i2 = 9;在创建完i2的引用变量后,因为在栈中已经有9这个值,便将i2直接指向9。这样,就出现了i1与i2同时均指向9的情况。最后i3也指向这个9。

成员变量和局部变量的 内存中的分配

对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。 形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。 成员变量存储在堆中的对象里面,由垃圾回收器负责回收。 如以下代码:

class BirthDate {    private int day;    private int month;    private int year;     public BirthDate(int d, int m, int y) {        day = d;        month = m;        year = y;    }    // 省略get,set方法………} public class Test {    public static void main(String args[]) {        int date = 9;        Test test = new Test();        test.change(date);        BirthDate d1 = new BirthDate(7, 7, 1970);    }     public void change(int i) {        i = 1234;    }}

对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:

  1. main方法开始执行:int date = 9; date局部变量,基础类型,引用和值都存在栈中。
  2. Test test = new Test();test为对象引用,存在栈中,对象(new Test())存在堆中。
  3. test.change(date); i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。
  4. BirthDate d1= new BirthDate(7,7,1970); d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
  5. main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(), new BirthDate()将等待垃圾回收。

3.属性 field(字段)

类的属性 又叫 成员变量, 又叫field(字段).

属性类的一个组成部分,一半是基本数据类型,也可以是引用类型(对象,数组).

属性 (访问修饰词: 就是访问范围), 属性类型, 属性名;

public

proctected

默认

private

可以是任意类型 包括基本类型或者引用类型.

属性不复制则是有默认值 其默认值和数组的一样

创建后,没有赋值会有默认值.

  • int\short\byte\long\ 都是0

  • false\double 0.0

float\double 0.0

  • char \u0000

  • boolean false

  • String utill

4.创建对象和类,访问属性的方法.

1.先声明后创建

Cat cat; //在栈里创建.

cat = new Cat(); //才开始在堆里创建空间, 如果String在常量池没有值 ,则创建和赋值这个值,给到堆,

2.直接创建

Cat cat = new Cat();

3.访问方法:

对象名.属性名

cat.name

cat.age

cat.color

5.对象的内存空间

注意看, 10是常量 , "小明"是字符串,在常量池创建 然后复制给堆的p1.name. (值传递) (这个值传递 传递的是一个地址信息)

p1赋值给了p2 (p2指向了p1)

所以 p2 与p1指向了堆的同一个对象地址

小结:

6.练习

注意: b=null 以后 b不再指向对象了. 所以报错.

第八章:方法

1.方法的概念

创建:

//猫类 class Cat{//属性String catName; //名字int age;String color; //成员方法(类里的方法)//添加一个speak 成员方法,输出一个“我是一个好人。”//1. public 表示方法公开//2. void 表示方法没有返回值//3. speak() speak是方法名,  () 形式参数列表//4. {}里 语句块(也就是方法体) public void speak(){System.out.println("我是一个好人");}}

方法的调用:

Cat cat2 =new Cat();//调用方法cat2.speak();//方法调用
class Method01{   int n;   //求和1-1000方法   public void sum(int n){   int sum = 0;   for (int i = 1;i <= n ; i++) {   sum+=i;   }   // sum = (1+n)*(n/2);    System.out.println(sum);   }   public int sum2(int n,int m){   int sum = n + m;   return sum;   }}Method01 m = new Method01();   m.sum(999);   int n =  m.sum2(111,1911);   System.out.println(n);4995002022

2.方法的调用机制原理

int[][] arr = {{1,1,23,412},{4123,4123,42},{4123,423}};DimansionalArray dimansionalArray = new DimansionalArray();dimansionalArray.getPrintlnDimansional(arr);class DimansionalArray{//打印二维数组   方法:驼峰原则public void getPrintlnDimansional(int[][] arr){for(int[] arr1:arr){for (int arr2:arr1) {System.out.print(arr2 + "\t");}System.out.println("");}}}

内存机制:

使用地址定位

3.方法的细节

1,访问修饰符

public protected 默认(就是不写) private

2.形式参数的类型:

//什么类型都可以  使用逗号隔开getSum(int a,int[][] b);

方法不能嵌套定义(方法里 禁止套娃)

3.同类 异类的方法调用

同类可以直接调用:

int[][] arr = {{1,1,23,412},{4123,4123,42},{4123,423}};DimArray dimArray = new DimArray();dimArray.getprintlnArr(arr);class DimArray{//打印二维数组public void printlnArr(int[][] arr){for(int[] arr1:arr){for (int arr2:arr1) {System.out.print(arr2 + "\t");}System.out.println("");}}public void getprintlnArr(int[][] arr){printlnArr(arr);}}

异类的方法调用

int[][] arr = {{1,1,23,412},{4123,4123,42},{4123,423}};DimArray dimArray = new DimArray();dimArray.getprintlnArr(arr);class DimArray{//打印二维数组public void printlnArr(int[][] arr){for(int[] arr1:arr){for (int arr2:arr1) {System.out.print(arr2 + "\t");}System.out.println("");}}    //A类中调用B类  不同包 不同修饰符 可调用的情况不一样public void getprintlnArr(int[][] arr){printlnArr(arr);Array01 array01 = new Array01();array01.hi();}}class Array01{public void hi(){System.out.println("hai");}}

4.方法练习(以后常见)

奇数偶数判断练习

int i = 11;OddEven odd =new OddEven();if(odd.isOdd(i)){// T ,是一个很常见的写法System.out.println(i+"是一个奇数");}else{System.out.println(i+"是一个偶数");}//Odd even judgment 奇偶判断class OddEven{//判断奇数public boolean isOdd(int i) {//return i % 2 != 0 ? true: false;        return i % 2 !=0; //(t 则奇数) (f 偶数) 直接丢进判断里}}

打印规定行列 字符.

//打印规定行 列 字符odd.print01(2,3,"u");public void print01(int row,int col,char c){for(int j = col;j >= 0; j--){for(int i = row;i >= 0; i--){System.out.print(c + " ");}System.out.println();}}

5.方法传参机制(基本数据类型 与 引用数据类型)

基本数据类型 在方法和main中拷贝的是值 而基本数据类型在栈中独立存在(因为方法栈,和main栈 ) 借给对方用一下而已.

引用数据类型

关键在于 引用类型也是 值传递但是传递的是地址信息 在方法中修改了 引用类型的 内容信息 是修改了常量池的信息.所以堆里(对象)所复制的信息也变了 而栈里的信息是地址信息 地址没变(修改) 所以main和方法里的引用类型的 内容是一样的

测试

p的对象引用到方法中,p = null 则表示 这个b栈指向的对象地址变为了空 所以原本的p.age还是10 一样的问题 (没有修改引用类型的(对象的) 内容)

克隆对象( 对象属性复制,但是是不同对象)

比较对象 可以使用hashcode 或者直接 == 进行比较 引用类型 的== 比较的是地址. 基本数据类型的 == 比较的是内容

6.方法递归调用

  • 明确递归的终止条件
  • 提取重复的逻辑,缩小问题的规模不断递去
  • 给出递归终止时的处理办法

方法自己调用自己.

递归: 解决分治 快排等排序算法的 基础 注意: 栈的 (先进后出原则) 直筒状.

阶乘问题:

Test01 test01 =new Test01();System.out.println((double)(test01.factorial(30)));class Test01{public int factorial(int n){if(n == 1){return 1;}else{return factorial(n - 1) * n;}}}

斐波那契数列

理解一下 是一个树状图

i = 5​            i= 4   +   i=  3     (i = 3)  +  (i = 2)   +   (i = 2) + (i = 1) (i = 2) + (i = 1) +   1    +         1 + 1                           3 + 2                         5    
//第十个斐波那契数列 的数是谁System.out.println(test01.fibonacci(10));//55//斐波那契数列public int fibonacci(int n){// 1 1 2 3 5 8 13 if(n == 1 || n == 2){return n = 1;}else{return fibonacci(n-1)+fibonacci(n-2);}

猴子吃桃问题

//猴子吃桃 第一天吃一半,并多吃了一个  往后每一天都吃一半加一颗// 最后一天 只有1颗桃子 给出天数 求第一天桃子数public int peach(int day){if(day == 1){return 1;}else{return ((peach(day-1)+1)*2);}}//求第一天多少颗桃子System.out.println(test01.peach(10)); 1534颗

迷宫问题:

迷宫问题, 迷宫从头到尾,

1.注意一个问题,上左下右,if 进行并列进行 则可以进行全部的可能的结果进行输出.

2.输出二维循环即可.

3.注意循环条件 (1.起始位置必须在限定范围之内) (2.不能碰墙壁)(3.不碰已经走过的路) (4.注意返回的false)

4.注意小球路径问题 下右上左 上右下左 两种

5.注意回溯问题 就是进入巷子以后,上下左右完全走不通的情况.

网上解法:

public class FunTest {//表示行  列static int ROW = 10;static int COL = 10;static boolean find = false;static int i = 1;//起点 终点  接受传入的起点与终点public static void Maze(char[][] arr,int start_row,int start_col,int end_row,int end_col){arr[start_row][start_col] = "S";if (start_row == end_row && start_col == end_col) {find = true;System.out.println("成功走出,路线图为:");printArr(arr);return;}// 上 判断上面的数是否能走if (judgeMave(arr,start_row - 1,start_col)) {//如果走了 那么传走了以后的坐标给下一次方法Maze(arr,start_row - 1,start_col,end_row,end_col);//如果程序不结束,表明此路不通,恢复该区域的标记arr[start_row - 1][start_col] = "1";}// 左 判断左面的数是否能走if (judgeMave(arr,start_row,start_col - 1)) {//如果走了 那么传走了以后的坐标给下一次方法Maze(arr,start_row,start_col - 1,end_row,end_col);//如果程序不结束,表明此路不通,恢复该区域的标记arr[start_row][start_col - 1] = "1";}// 下 判断下面的数是否能走if (judgeMave(arr,start_row + 1,start_col)) {//如果走了 那么传走了以后的坐标给下一次方法Maze(arr,start_row + 1,start_col,end_row,end_col);//如果程序不结束,表明此路不通,恢复该区域的标记arr[start_row + 1][start_col] = "1";}// 右 判断右面的数是否能走if (judgeMave(arr,start_row,start_col + 1)) {//如果走了 那么传走了以后的坐标给下一次方法Maze(arr,start_row,start_col + 1,end_row,end_col);//如果程序不结束,表明此路不通,恢复该区域的标记arr[start_row][start_col + 1] = "1";}}//判断是否可以移动public static boolean judgeMave(char[][] arr,int start_row,int start_col){//黑色区域 返回false  否则true  //返回默认是false   关键是这个条件问题 1. 起始位置在边界内  2.当前位置 不能是墙壁 不能是已经走过的return start_row >= 0 && start_row <= ROW - 1 && start_col >= 0 && start_col <=COL -1 &&arr[start_row][start_col] != "0" && arr[start_row][start_col] != "S";}//输出行动路线public static void printArr(char[][] arr){for (int i = 0;i < arr.length;i++ ) {for(int j = 0; j < arr[i].length;j++){System.out.print(arr[i][j]+" ");}System.out.println();}}public static void main(String[] args) {//迷宫问题, 找最短路线 0表示墙壁 1表示可以通行 起点[1,1] 终点[8,8]char[][] arr = {{"0","0","0","0","0","0","0","0","0","0"},{"0","1","1","1","1","1","1","1","1","0"},{"0","0","0","0","0","0","0","1","1","0"},{"0","0","0","1","0","1","1","1","1","0"},{"0","0","0","0","0","1","1","0","1","0"},{"0","0","0","0","0","1","1","0","1","0"},{"0","1","1","1","1","0","0","0","1","0"},{"0","1","1","1","1","0","0","0","1","0"},{"0","1","1","1","1","1","1","0","1","0"},{"0","0","0","0","0","0","0","0","0","0"},};// printArr(arr);Maze(arr,1,1,8,8);}}

韩老解法:

计算最短路线,使用枚举法 或者 图方法.上面的就是枚举法

public class MiGong{public static void main(String[] args) {//思路//1.创建迷宫 8 7//2.0表示能走  1表示障碍int[][] map = new int[8][7];//将最上最下设成1,for (int i = 0;i < 7 ;i++ ) {map[0][i] = 1;map[7][i] = 1;}//将左右全部设置为1,for(int i = 0;i < 8; i++){map[i][0] =1;map[i][6] =1;}map[2][2] =1;map[3][1] =1;map[3][2] =1;map[4][3] =1;//输出当前地图System.out.println("初始地图");for(int[] arr: map){for (int arr1: arr) {System.out.print( arr1 +" ");}System.out.println();}T t = new T();t.findWay(map,1,1);//输出结束后的地图System.out.println("找完的地图");for(int[] arr: map){for (int arr1: arr) {System.out.print( arr1 +" ");}System.out.println();}}}class T {//使用递归方法来解决迷宫问题//输入二维数组,起始行 i, 起始列 j;//专门找路径 找到 返回true,返回值 false.//初始化为 (1,1)//因为是递归找路 所以有一下原则:// 1. 0表示能走  1表示障碍 2 表示可以走 // 3.表示走过的路,但是走不通 是死路// 当 map[6][5] = 2 表示找到通路 否则继续找// 下右上左   上 右 下 左  回溯问题(设置3 不能走的地方)  // 和求最短距离呢 (穷尽法,图)public boolean findWay(int[][] map,int i, int j){if(map[6][5] == 2){ //说明已经找到return true;}else{if(map[i][j] == 0){ //当钱位置为0 表示可以走//开始下右上左//假设能走通map[i][j] = 2;//下 右 上 左if(findWay(map,i+1,j)){return true;}else if(findWay(map,i,j+1)){return true;}else if(findWay(map,i-1,j)){return true;}else if (findWay(map,i,j-1)) {return true;}else {map[i][j] = 3;return false;}/*//上 右 下 左if(findWay(map,i-1,j)){return true;}else if(findWay(map,i,j+1)){return true;}else if(findWay(map,i+1,j)){return true;}else if (findWay(map,i,j-1)) {return true;}else {map[i][j] = 3;return false;}*/} else {//1 2 3 都不走return false;}}}}

汉诺塔问题:

三个柱子 64个叠圆盘, 三个柱子 规则: 1.一次只能移动一个圆盘 2.小的只能放在大的上面.假如一秒钟移动一次,移动完需要5845.54亿年.

注意汉诺塔中,进行调用的时候 的adc的代指和作用. 最终目的就是 将最大的那个盘放在目标盘,其他盘的位置 需要注意顺序 直接用2个去测试和查看.

解决这样的问题可以尝试用分治算法,将移动多个圆盘的问题分解成多个移动少量圆盘的小问题,这些小问题很容易解决,从而可以找到整个问题的解决方案。

public class HanNuoTa{//尝试使用数组进行.public static void main(String[] args){T t = new T();//A为初始,B为辅助, C为目标t.hanNuoTa01(2,"A","B","C");}}class T{// num 表示圆盘数,a b c表示三个塔int i = 1;public void hanNuoTa01(int num,char a,char b,char c){//当只有一个圆盘的时候 就将a转移到cif(num == 1){System.out.println("第" + i + "次:从" + a + "移动到" + c);i++;}else{//多个盘 看作只有两个 先从三盘开始盘算// 递归调用 hanoi 函数,将 num-1 个圆盘从起始柱移动到辅助柱上,整个过程的实现可以借助目标柱hanNuoTa01(num - 1,a,c,b);// 将起始柱上剩余的最后一个大圆盘移动到目标柱上System.out.println("第" + i + "次:从" + a + "移动到" + c);i++; // 递归调用 hanoi 函数,将辅助柱上的 num-1 圆盘移动到目标柱上,整个过程的实现可以借助起始柱  hanNuoTa01(num - 1,b,a,c);}}}

八皇后问题:

就是8*8的国际象棋棋盘上 摆放8个皇后,使其不能互相攻击

皇后的攻击范围是:同一行,同一列,同一斜线上. 问有多少种摆放方法。

还是回溯问题:

import java.util.Scanner;public class NQueen {    static int[] q = new int[20];    static int count = 0;    public static void n_queens(int k, int n) {        int j;        if (k > n)            print(n);        else {            for (j = 1; j <= n; j++) // 试探第k行的每一列,找到符合要求的列            {                if (isSafe(k, j)) {                    q[k] = j;                    n_queens(k + 1, n); // 在确认第 k 行皇后位置的前提下,继续测试下一行皇后的位置                }            }        }    }    public static boolean isSafe(int k, int j) {        int i;        for (i = 1; i < k; i++) {            // 如果有其它皇后位置同一列上,或者位于该位置的斜线位置上,则该位置无法使用            if (q[i] == j || Math.abs(i - k) == Math.abs(q[i] - j))                return false;        }        return true;    }    // 输出 N 皇后问题的解决方案    public static void print(int n) {        int i, j;        count++;        System.out.println("第 " + count + " 个解:");        for (i = 1; i <= n; i++) // 行        {            for (j = 1; j <= n; j++) // 列            {                if (q[i] != j)                    System.out.print("x");                else                    System.out.print("Q");            }            System.out.println();        }        System.out.println();    }    public static void main(String[] args) {        System.out.println("请输入皇后个数:");        Scanner sc = new Scanner(System.in);        int n = sc.nextInt();        n_queens(1, n);        System.out.println("共有 " + count + " 种摆放方式");    }}

4.方法的重载

表示 允许方法名一致但是形参列表必须不一样 形参参数名随意返回类型不限制就是用了适应不同情况.

好处

  • 减轻了起名字的麻烦

  • 减轻了记名字的麻烦

注意问题:

  1. 方法一定相同

  2. 形参列表一定不一样, 形参参数名没要求

  3. 返回类型不限制

1.细节问题:

m(2.4,400,5.2); //调用的三个  因为 400对应的是int 优先不类型转换的数.//:方法重载public void m(int a,int b, int c){    double max1 = n1 > n2 ? n1 : n2;    return max1 > n3 ? max1 :m3;}public void m(double a,double b, double c){    double max1 = n1 > n2 ? n1 : n2;    return max1 > n3 ? max1 :m3;}public void m(double a,int b, double c){    double max1 = n1 > n2 ? n1 : n2;    return max1 > n3 ? max1 :m3;}

2.可变参数

允许同一个类中多个同名同功能 但参数个数不同的方法 装载成一个方法

方法名(数据类型... 形参名){

}

可变参数:

System.out.println(test01.sum(1,23,4123,4123,4211,4535,123,24));//17163public int sum(int... nums){//可变形参 本质是一个数组    System.out.println("接受的桉树个数为: nums.length");    int res = 0;    for(int i  = 0; i < nums.length; i++){        res += nums[i];    }    return res;}
注意事项
  1. 可变参数的实参可以是0个或者任意多个 [0,+∞)
  2. 可变参数的实参可以为数组(同类型用数组传进方法中.) 可以是数组 注意这个
  3. 可变参数的本质就是数组 本质就是数组
  4. 可变参数可以和普通类型的参数一起放在形参列表,但是必须要放在最后, end place
  5. 一个形参列表只能出现一个. only on
int[] i = {1,2,312,4213,42,45,214};System.out.println(test01.sum(i));// 接受的数  + 7// 4829public int sum(int... nums){//可变形参 本质是一个数组    System.out.println("接受的桉树个数为: + "+nums.length);    int res = 0;    for(int i  = 0; i < nums.length; i++){        res += nums[i];    }    return res;}

实例:

System.out.println(test01.showScore("3年级",100,231,434,423,54));//3年级有5门科目,全部总成绩为:1242.0public String showScore(String str,double... score){double totalScore = 0;for (int i = 0;i < score.length ; i++ ) {totalScore += score[i];}return str + "有" + score.length + "门科目,全部总成绩为:" + totalScore;}

5.作用域Scope(作用域)

1.变量就是:(属性)成员变量和 局部变量.

局部变量就是 成员方法内定义的变量

全局变量 :属性, 作用与整个类体的. Cat类 catName eat 等

局部变量: 除了书信外的其他变量 作用域在定义的代码块里

2.细节

  1. 属性和局部变量可以重名(就近原则访问)
  2. 同一作用域,不能重名
  3. 属性生长:周期长,随着对象的创建而创建,随着对象的死亡而死亡,
  4. 局部变量 :生长周期短,随着代码块的执行而创建,伴随代码块的死亡而死亡.
  5. 全局变量: 也就是属性 可以被本类适应,或者其他类(对象调用).
  6. 局部变量: 只能是本类中对应的方法中使用,
  7. 修饰符不同, 全局变量可以加修饰符 局部变量不能加修饰符

属性 在类装载器装载后,在方法区里出现

而局部变量 则是在栈(基本类型) 在堆(引用类型 ) 中.

3.访问类中属性(全局变量)的方法。

//main 方法Test01 test01 =new Test01();System.out.println(test01.name);T t = new T();t.test01();t.test02(test01);//jack//jack//jackclass T{public void test01(){Test01 test01 = new Test01();System.out.println(test01.name);}public void test02(Test01 test01){System.out.println(test01.name);}}class Test01{String name = "jack";}

6.构造器(构造方法): constructor(建造师)

1.构造器的定义

理解为 构建类的一种方法 不同构造器可以构造不同的类.

方法名和类名一致,

没有返回值

在创建对象中,系统会自动的调用该类的构造器完成对对象的初始化.

参数列表 与 成员方法的规则一样.

Constructor01 constructor01 = new Constructor01("lxh",100);System.out.println(constructor01.name + "和"+ constructor01.age);class Constructor01{String name;int age;//形参列表的名字不能和全局变量(属性)的名字一样 不然会就近原则.//输出null 等默认值public Constructor01(String pName,int pAge){//完成对象的初始化.name = pName;age = pAge;}}

2.构造器的细节

  1. 可以重载
  2. 类名和构造器名一致
  3. 没有返回值
  4. 是完成对象的初始化 而不是创建对象 所以需要已经有了属性
  5. 创建对象时,系统自动调用该类的构造方法.
  6. 形参列表和属性名字不能完全一致, 不知道IDEA中是不是可以优化.
  7. 默认有一个无参构造器就是属性全是默认值 自行创建构造器后, 空构造器就失效了 需要自行再创建.
//自行创建了构造器后 不能再使用空构造器 所以需要初始化一个空构造器.Constructor01 constructor01 = new Constructor01();System.out.println(constructor01.name + "空构造器"+ constructor01.age);Constructor01 constructor02 = new Constructor01("lxh",100);System.out.println(constructor02.name + "第一个构造器"+ constructor02.age);Constructor01 constructor03 = new Constructor01("lxh");System.out.println(constructor03.name + "第二个构造器"+ constructor03.age);class Constructor01{String name;int age;//形参列表的名字不能和全局变量(属性)的名字一样 不然会 不是属性了    //就近原则.//输出null 等默认值public Constructor01(){             age = 18;        }public Constructor01(String pName,int pAge){//完成对象的初始化.name = pName;age = pAge;}public Constructor01(String pName){//完成对象的初始化.name = pName;            age = 18;}}

"javap"反编译

直接对 类 继续反编译.C:\Users\qianl\Desktop\java快速学习\javacode>javap Constructor01.classCompiled from "Test.java"class Constructor01 {  java.lang.String name;  int age;  public Constructor01();  public Constructor01(java.lang.String, int);  public Constructor01(java.lang.String);}

3.对象的创建流程

1,首先 main方法的先运行. 先加载Person类, 只会加载一次

2.然后给堆 new一个 对象 (分配堆中的空间) 对象先根据类的属性初始化age = 90; name = "null";

3.由于name 是String类型 所以在常量池划定一个区域, 填写null 堆中是其地址 .

4.开始调用构造器 ,将 小倩赋值到常量池, 将 90 替换成 20;

5.然后再将对象的地址赋值给p.

4.this关键字

java虚拟机 给每个对象分配了this 代表当前对象 使用对象可以解决 变量的形参命名问题

class Constructor01{String name;int age;//形参列表的名字不能和全局变量(属性)的名字一样 不然会就近原则.//输出null 等默认值public Constructor01(){ age = 18;}    //this 演示public Constructor01(String name,int age){//完成对象的初始化. //this.name 表示该类的属性  后面的name 表示就近原则this.name = name;this.age = age;}}

this的理解

this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。

  • 第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
  • 第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。//和构造器差不多 谁调用这个方法 this指代的就是哪个对象
  • 第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  • 第四种是 apply 、 call 和 bind调用模式,这三个方法都可以显示的指定调用函数的 this 指向。

这四种方式,使用构造器调用模式的优先级最高,然后是 apply、call 和 bind 调用模式,然后是方法调用模式,然后是函数调用模式。

注意

1.this 可以访问构造器和方法.

2.区分属性与局部变量

3.语法 this.方法名(参数列表)

4,访问构造器 this(参数列表)只能在构造器中使用且必须在第一个语句

5,不能在类定义的外部使用,只能在类定义的方法中使用.

this 方法使用: 注意 继承的时候 this指代的是本类的方法. 用于解决方法同名的时候

T t = new T();t.f2();//方法: f2//方法: f1//方法: f1}}class T{    //this方法访问public void f1(){System.out.println("方法: f1");}public void f2(){System.out.println("方法: f2");//类内直接调用方法;f1();//继承时调用父类方法.this.f1();}}

this 构造器使用: 只能在构造器中使用

T t = new T();System.out.println(t.name + "和" + t.age);//这是有参构造器//hhn和100class T{String name;int age;//如果有this 访问构造器 必须在类中的第一个语句public T(){this("hhn",100);}public T(String name,int age){System.out.println("这是有参构造器");this.name = name;this.age = age;}}

this 调用属性

每一个对象会有一个this 指代对象自身.

this的hashCode 表示的是在哈希表内的地址 不是实际的内存地址.

5.hashcode

可以直接点出hashcode.

hashcode代表对象的地址说的是对象在hash表中的位置

只要是判断是不是同一个对象, 所以 在重写equals的时候也要重写hashcode.

6. compareTo 比较方法

用于判断 是否与另一个类 是否相等, 如果一样则返回true 否则返回false.

T t = new T();/*System.out.println(t.name + "和" + t.age);t.f2();*/T t1 = new T("lxh",200);System.out.println(t.compareTo(t1));// false}}class T{String name;int age;//如果有this 访问构造器 必须在类中的第一个语句public T(){this("hhn",100);}public T(String name,int age){System.out.println("这是有参构造器");this.name = name;this.age = age;}public boolean compareTo(T t){//名字 年龄相等 才返回truereturn this.name.equals(t.name) && this.age == t.age;}}

章节练习

1.求出某个double数组的最大值, 并返回 当然用排序算法更好

我自己写的:

double[] d = {1.21,421.3,442.3,436.64,412,42};A01 a01 = new A01();double d1 = a01.max(d);System.out.println(d1);class A01{    public double max(double[] d1){        double max01 = 0;        for(double d : d1){            if(max01 < d){                max01 = d;            }        }        return max01;    }}

注意健壮性后 自动装箱 自动拆箱的问题

double[] d = null;A01 a01 = new A01();Double d1 = a01.max(d);if(d1 != null){System.out.println(d1);}else{System.out.println("请保证传入数组不是 空 或 \"null\" ");}}}class A01{//注意要转变成包装类  不然 d1 != null 无法比较// 且 返回值 null 也无法转换.    public Double max(double[] d1){    //传进来不能为null 因为引用类型可以用null, 且长度不能为0;    if (d1 != null && d1.length > 0) {   double max01 = d1[0];//假定第一个是最大值        /*for(double d : d1){            if(max01 < d){                max01 = d;            }        }*/        for(int i = 1; i < d1.length; i++){        if(max01 < d1[i]){        max01 = d1[i];        }        }        return max01;//返回最大值    } else {    return null;    }     }}

字符串与字符数组

String[] strs = {"jack","dafa","wifu","哈哈嗨"};A02 a02 = new A02();int a = a02.find(null,strs);if(a != -2){System.out.println(a);}else{System.out.println("不能为空");}//find 查找字符串是否在字符串数组中, 返回索引 否则 -1;class A02{public int find(String findStr,String[] strs){if(findStr != null && strs != null && strs.length > 0){for(int i = 0; i < strs.length; i++){if(findStr.equals(strs[i])){return i;}//值等等/*if(findStr == (strs[i])){return i;}*/}return -1;}else{return -2;}}}

书本价格

Book book = new Book("name",151);book.info();book.updatePrice();book.info();class Book{String bookName;int price;public Book(){}public Book(String bookName,int price){this.bookName = bookName;this.price = price;}public void updatePrice(){//如果方法中没有price 局部变量 this.price 等价于 price;if(this.price >= 150){this.price = 150;}else if(this.price > 100){this.price = 100;}}public void info(){System.out.println(bookName + "价格" +price);}}

计算类 重点在返回包装类上 以承接null 值

//计算类class Cale{//加 减 乘 除(除数为0需要提示)double num1;double num2;public Cale(){}public Cale(double num1,double num2){this.num1 = num1;this.num2 = num2;}public double jia(){return num1 + num2;}public double jian(){return num1 - num2;}public double cheng(){return num1 * num2;}//不能返回 -1 因为可能就是-1 所以返回空  null只能包装类使用public Double chu(){if (num2 == 0) {System.out.println("被除数不能为0");return null;}else{return num1 / num2;}}}

第九章IDEA

1.快捷键:

自定义模板

2.包的本质分析

解决类的命名问题

使用了 小强的Dog

然后要使用小明的 就要使用包名 点出小明的Dog

包的命名规范

错错对 一个有class关键字 一个数字开头

lang的 直接用 不用引入

包的引入

可以只引入包下一个类 (需要什么 导入什么)

也可以 . * 导入所有类 不建议全部导入

//包必须在最上面 而且 只能有一个package PackageTest;import java.util.Arrays;/** * @Auther: qianl * @Date: 2022/10/18 02:53 * @Description: */public class Import01 {    public static void main(String[] args) {        int[] arr = {1, 3, 421, 43, 5, 52, 55, 1, 2};        Arrays.sort(arr);        for(int i = 0;i < arr.length; i++){            System.out.print(arr[i] + "\t");        }    }}

3.访问修饰符 属性或方法。

public公开的

protected受保护的 对子类和同一个包中的类公开

默认 没有修饰符号 向同一个包的类公开

private私有级 只有类本身可以访问 不对外公开

同类 就是本类

同一个包 只有私有的不能调用

不同包里 只有public 才能访问,

类的修饰符 只有 公开和默认才能修饰。

4.(重点)封装 encapsulation

封装 (encapsulation) 就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作,才能对数据进行操作(增删改查)

封装练习 1 Account 账户
package Encap;/** * @Auther: qianl * @Date: 2022/10/19 00:25 * @Description: *///账号账户public class Account {    private String name;    private double balance;    private String password;    public Account() {    }    public Account(String name, double balance, String password) {        setName(name);        setBalance(balance);        setPassword(password);    }    public String getName() {        return name;    }    //姓名长度为2 3 4    public void setName(String name) {        if (name.length() >= 2 && name.length() <= 4) {            this.name = name;        } else {            System.out.println("姓名要求(长度为2 3 4位),默认值 无名");            this.name = "无名";        }    }    public double getBalance() {        return balance;    }    public void setBalance(double balance) {        if (balance > 20) {            this.balance = balance;        } else {            System.out.println("余额不能少于20 默认值为0");        }    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        if (password.length() == 6) {            this.password = password;        } else {            System.out.println("密码必须为6位 默认密码000000");            this.password = "000000";        }    }    public void showInfo() {        //密码可以增加权限的校验        System.out.println("账号信息 name=" + name + "余额" + balance + "密码" + password);    }}
package Encap;/** * @Auther: qianl * @Date: 2022/10/19 00:42 * @Description: */public class TestAccount {    public static void main(String[] args) {        Account account = new Account();        account.setName("jack");        account.setBalance(19);        account.setPassword("213421");        Account account1 = new Account("shi",90,"adcaca");        account1.getBalance();    }}

5.(重点)继承 extends(继承 扩展)

类的属性与方法很多相同, 使用继承 只写自己需要新加的 从重复的类中抽象出父类.

父类又叫 超类 基类

继承的关系示意图

继承测试:

父类:

package extend_.improve;/** * @Auther: qianl * @Date: 2022/10/19 22:06 * @Description: *///小学生和大学毕业生的父类public class Student {    public String name;    public int age;    private double score;//成绩    public void setScore(double score) {        this.score = score;    }    public void showInfo() {        System.out.println("学生名:" + name + "年龄" + age + "成绩" + score);    }}

子类 puplic

package extend_.improve;/** * @Auther: qianl * @Date: 2022/10/19 22:08 * @Description: *///继承学生类public class Pupil extends Student {    public void testing(){        System.out.println("小学生" + name + "考小学数学");    }}

子类: graduate

package extend_.improve;/** * @Auther: qianl * @Date: 2022/10/19 22:08 * @Description: */public class Graduate extends Student {    public void testing(){        System.out.println("大学生" + name + "考高等数学");    }}

测试类 Test

package extend_.improve;/** * @Auther: qianl * @Date: 2022/10/19 22:14 * @Description: */public class TestStudent {    public static void main(String[] args) {        Pupil pupil = new Pupil();        pupil.name = "金色";        pupil.age = 7;        pupil.testing();        pupil.setScore(60);        pupil.showInfo();        System.out.println("============");        Graduate graduate = new Graduate();        graduate.name = "银色";        graduate.age = 18;        graduate.testing();        graduate.setScore(100);        graduate.showInfo();    }}/*小学生金色考小学数学学生名:金色年龄7成绩60.0============大学生银色考高等数学学生名:银色年龄18成绩100.0*/
细节:

1.子类继承了父类的全部属性和方法, 但是私有的属性和方法不能在子类直接访问,需要通过公共的方法去访问.(子类不能直接访问私有属性与方法, 但是能间接使用)

使用get方法 获得private属性

使用callTest400的方法去调用私有方法.

下面是运行逻辑

先是生成父类构造器 然后子类构造器

然后调用子类方法 输出 public protected 默认

通过getN4 获得私有属性

然后通过方法调用 public protected 和默认 的方法

使用公共方法调用私有方法

Base()...Sub()....100 200 300 400public test100protected test200默认 test300private test400

2.子类必须调用父类的构造器,完成父类的初始化

看上面的例子 创建子类 Sub 先完成了父类的构造器 Base;

3.创建子类对象,不管使用子类的哪个构造器,默认调用父类无参,没有提供无参则必须在子类构造器用 super去指定使用父类的哪个构造器完成父类的初始化工作 否则编译不通过.

在子类中先会有super(); 去调用父类的无参构造器. 要不就不写 默认调用无参

public Sub() {//        super();  默认有super        System.out.println("Sub()....");    }

子类调用有参构造器 然后由于父类的无参被有参构造器覆盖 (默认的无参也就没有了) 所以需要用super(参数); 写明调用父类的哪个有参构造器

4.如果需要指定父类的某一个构造器, 需要super(参数列表)显式的调用

5.super必须在构造器的第一行

6.super() 和this()都只能放在第一行 所以二者不能共存于一个构造器中

7.java中所有类 都是Object类的子类 ( ctrl + H 可以看到继承关系) 所以 一定是先运行Object类才往下运行其他的子类.

8.父类构造器的调用不限于直接父类,可以一致追溯到Object类 (顶级父类 ) 比如重写equals方法等.

9.子类最多只能继承一个父类(直接继承) java中是单继承机制, 如何A类继承B类和C类 (再写一级父类 或者接口)

10.不能滥用继承 子类和父类之间必须满足is-a的逻辑关系. (is-a 是一种)

Person is a Music?

Music extends Person

Animal

Cat extends Animal

继承的本质分析(重要)

主要注意内存的布局

先加载 再分配地址 和创建对象.

会将子类和父类之间的查找关系给建立好

1,先找到Object 等父类 从高到低 加载到方法区,

2.依据继承关系 在常量池创建 各个父类子类的存储空间. 存储基本数据

3,创建新对象的时候 将在堆中创建一个 内存, 将数据指向常量池.

4.最后将堆内地址指向son 这个对象名.

数据调用时遵循"就近原则"

​son.name = " 大头儿子"

如果没有该数据 则返回上一级父类.

​例如: son.age = 39 返回的是父类的数据.

​son.habby = "旅游"

  • **如果 在父类有私有属性 age 而爷爷类有公有属性 age 不会跳过父类 而是直接报错 **

Object类都没有这个属性也会报错.

继承课堂练习1:

1.B(); 调用的B() 然后自动super(); 由于有this(" abc") 传进了第二个构造器

2.调用默认空构造器 输出: a

3.输出构造器 B(String name) b name

4.输出B()的空构造器 b

继承课堂练习2:

1,进C();

2,进C(String name);

3,super("hahah") 进B(String Nmae);

4,进A();

所以输出 先是 : A类 ---> hahah B类有参数-----> C类的有参-----> C类的无参构造

继承课堂练习 3:

题目如下:

输出结果:

cpu=i7Memory30Hard_disk50brandintercolorblue

package extend_.improve;import java.time.temporal.Temporal;/** * @Auther: qianl * @Date: 2022/10/20 18:52 * @Description: */public class TestExercise {    public static void main(String[] args) {        NotePad notePad = new NotePad("i7",30,50,"inter","blue");        notePad.printNotePadInfo();    }}class Computer{    private String CPU;    private int Memory;    private int Hard_disk;    public Computer() {    }    public Computer(String CPU, int memory, int hard_disk) {        this.CPU = CPU;        Memory = memory;        Hard_disk = hard_disk;    }    //返回属性信息    public String getDetails(){        return "cpu=" + CPU + "Memory" + Memory + "Hard_disk" + Hard_disk;    }    public String getCPU() {        return CPU;    }    public int getMemory() {        return Memory;    }    public int getHard_disk() {        return Hard_disk;    }}class PC extends Computer {    private String brand;    public PC() {    }    //这里自动构造器的调用.    public PC(String CPU, int memory, int hard_disk, String brand) {        super(CPU, memory, hard_disk);        this.brand = brand;    }    public String printInfo(){        return getDetails() + "brand" + brand;    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }}class NotePad extends PC{    private String color;    public NotePad(String CPU, int memory, int hard_disk, String brand, String color) {        super(CPU, memory, hard_disk, brand);        this.color = color;    }    public void  printNotePadInfo(){        System.out.println(printInfo() + "color" + color);    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}

6.super关键字

基本介绍:

super代表父类的引用,用于访问父类的属性\方法\构造器,

访问父类的属性,但不能访问父类的private属性 super.属性名

访问父类的方法,不能访问父类的private属性 super.方法名(形参列表)

访问父类的构造器 只能放在构造器的第一句,只能出现一句 不能和this公用.

不能调用私有属性,私有方法

调用父类构造器的好处,

分工明确,父类属性由父类初始化,子类属性由子类初始化.

子类中有父类中的成员(属性和方法) 重名的时候, 为了访问父类成员,必须使用super 没有重名 则super this 直接访问 都是一样的效果.

构造器不能一起用,但是调用属性是可以的

找方法的过程

super() 是一级一级往上找 找到为止, 当然也可能被 private方法截胡

7.(重点)重写方法

注意事项 返回类型 方法名(形参列表) 全都要一样. 或者返回类型是父类的子类才行.

2,子类不能缩小父类方法的访问权限, 就是public --> protected ----> 默认 ----->private .

名称范围方法名形参列表返回类型修饰符
overload(重载)本类一致类型,个数,顺序至少一个不同无要求无要求
override(重写)父子类一致相同子类重写的返回类型与父类一致.或者是其子类(例如 返回类型String是Object的子类)不能缩小范围
重写方法练习override

1.编写一个Person类 包括属性/perivate(name age) 构造器\方法 say(返回自我介绍的字符串)

2,编写一给Student类 继承Person类,增加id score属性(private) 以及构造器,定义say方法(返回自我介绍的信息,)

3.在main中 分别创建Person和Student对象,调用say方法输出自我介绍.

使用super.方法来复用

8.(重点)多态

对象: 属性看编译类型 方法看运行类型(向上找)

主要解决同一事件 不同对象的调用问题

多态的具体体现

1.方法的多态 () 使用重写和重载体现)

传入不同的参数 可以调用不同的sum方法, 就体现了多态.

使用A.say() 方法 或者B.say()方法 也是一种多态

2.对象的多态(重点) 一个父类 多个子类 父类的引用(引用类型)指向(接收)子类的对象

(1) 一个对象的编译类型和运行类型可以不一致, (也可以一致)

(2)编译类型在定义对象时,就确定了,不能改变

(3)运行类型是可以变化的

(4)编译类型看定义时=号的左边,运行类型看 = 号的右边

Animal animal = new Dog(); 父类的引用 指向子类的对象 new的才是对象,

animal的编译类型是Animal 运行类型是Dog();

animal = new Cat() animal的运行类型变成了Cat ,编译类型还是Animal;

父类

public class Animal {    public void cry(){        System.out.println("Animal cry() 动物在叫 牙~~~~");    }}

子类

public class Cat extends Animal {    public void cry(){        System.out.println("小猫 喵喵叫");    }}

子类

public class Dog extends Animal {    public void cry(){        System.out.println("小狗 汪汪叫");    }}

运行

public class TestPolyObject {    public static void main(String[] args) {        //创建一个父类模板.然后通过父类 指向(接收)不同的子类对象  向上自动转型 , 实现各个子类的方法.        //编译类型是animal 运行类型是Dog        Animal animal = new Dog();        animal.cry(); //因为运行时,执行到该行,animal的运行类型是Dog 所以这个cry是Dog的cry方法        animal = new Cat();        animal.cry(); //小猫喵喵叫  这时候运行的是小猫的方法.    }}

3.多态的细节:

1.多态的前提 封装和继承

2.向上转型(自动)

向上转型

本质:父类的引用指向子类的对象

父类:

package objectpoly_.detail_;/** * @Auther: qianl * @Date: 2022/10/21 04:44 * @Description: */public class Animal {    String name = "动物";    int age = 10;    public void sleep(){        System.out.println("睡");    }    public void run(){        System.out.println("跑");    }    public void eat(){        System.out.println("吃");    }    public void show(){        System.out.println("hello,你好");    }}

子类

package objectpoly_.detail_;/** * @Auther: qianl * @Date: 2022/10/21 04:46 * @Description: */public class Cat extends Animal {    public void eat(){//方法的重写        System.out.println("猫吃鱼");    }    public void catchMouse(){//特有的方法 猫捉老鼠        System.out.println("猫捉老鼠");    }}

运行:

package objectpoly_.detail_;/** * @Auther: qianl * @Date: 2022/10/21 04:48 * @Description: */public class PolyDetail {    public static void main(String[] args) {        //父类引用 = new 子类类型();        Animal animal = new Cat();        Object obj = new Cat();//也可以  因为是父类        //编译阶段,可以调用父类的方法, 能调用什么方法(属性) 就看编译类型.        //而且依然遵循访问权限.        //最终实现效果 还是看子类的具体实现,  还是从子类开始找方法,然后往上寻找        animal.run();//跑        animal.eat();//猫吃鱼   实现的是子类重写后的方法.        animal.sleep();//睡        animal.show();//hello,你好        ((Cat) animal).catchMouse();  //猫捉老鼠     需要运行子类的方法 需要强制转换.    }}
向下转型

子类的引用指向父类引用

1.只能强转父类引用 ,不能强转对象 (对象不能改变,只能改变引用.)

2.要求父类的引用必须指向的是当前目标类型的对象

3.可以调用子类的类型中所有成员

接续上面的

//向下转型  编译类型:cat  运行类型:Cat 强转了cat        //(1)子类类型 引用名 = (子类类型) 父类引用        Cat cat = (Cat) animal;        cat.catchMouse();// 猫抓老鼠        //(2)要求父类的引用必须指向当前目标类(也就是现在的子类)的对象        //就是上面 必须是 (animal的引用 指向的是 Cat的对象) 才能这样强转.        //想向下转型 必须先向上转型.
细节:

(1) 属性没有重写, 属性的值看编译类型.

(2) 使用instanceOf比较操作符,判断对象的类型是否位XX类型或者XX类型的子类型.

(1)!!!!!!!

向上转型 属性看编译类型.

//直接就看编译类型, 编译类似是谁 属性就是谁.

(2)!!!!!!!!!!!!!!!!!!!!!!!

instanceOf 判断类是不是某一个类 或其子类

还是判断的编译类型都是true.

不是该类或者子类 所有 false

多态练习:

练习1
  1. 可以
  2. 可以 double 强转 long
  3. 结果为 13
  4. 可以
  5. int类型强转boolean 不行 boolean是true和flase
  6. 可以 "Hello" 是String类型 是Object的子类
  7. 向下转型 obj原本就是指向 String类型 所有可以强转
  8. "Hello"
  9. 可以 Integer(5) 就是int类型的包装类, 是Object的子类
  10. 不可以 因为objPri原本指向Integer类型
  11. 可以. 向下转型
练习2
属性看编译类型, 方法看运行类型

s.count 编译类型是Sub

所以输出的是 20

方法看的是运行类型

s.display 调用的是自己的方法,返回 this.count

输出的还是 20

编译类型转成了Base类型

b == s true 指向的是同一个对象 Sub();

输出 10 属性看编译类型

方法调用 是看运行类型 所有输出的是Sub的方法 输出20

20 20 true 10 20

9.动态绑定机制

属性看编译类型, 方法看运行类型

原则如下:

1,当调用对象方法的时候,该方法会和该对象内存地址/运行类型绑定.

2.当调用对象属性时,没有动态绑定机制, 哪里声明,哪里使用

3.当方法内使用属性的时候 (不是调用的情况 ) 依据就近原则. 获取属性.

package Dynamic;/** * @Auther: qianl * @Date: 2022/10/21 20:43 * @Description: */public class DynamicBinding {    public static void main(String[] args) {        A a= new B();        System.out.println(a.sum());// 方法看运行类型  getI() 看本类方法 (return i)也是看本类就近原则. 40        System.out.println(a.sum1());// 方法看运行类型 i看本类  30        //当子类的sum 方法删除的话.        System.out.println(a.sum());// 匹配父类的方法, 又调用了方法getI() 又去找子类  所有是 20 + 10;        //当子类的sum1 方法删除的话.        System.out.println(a.sum1());// 匹配父类的方法,因为i是全局属性 就近原则看本类 所以是 20;    }}class A{    public int i = 10;    public int sum(){        return getI()+10;    }    public int sum1(){        return i + 10;    }    public int getI(){        return i;    }}class B extends A{    public int i = 20;    public int sum(){        return getI()+20;    }    public int sum1(){        return i + 10;    }    public int getI(){        return i;    }}

10.多态的应用(多态数组)

父类:

package polyarr;/** * @Auther: qianl * @Date: 2022/10/21 22:04 * @Description: */public class Person {//父类    private String name;    private int age;    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String say(){        return name+" "+ age+ " ";    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

子类:

package polyarr;/** * @Auther: qianl * @Date: 2022/10/21 22:06 * @Description: */public class Student extends Person {    private double score;    public Student(String name, int age, double score) {        super(name, age);        this.score = score;    }    public double getScore() {        return score;    }    public void setScore(double score) {        this.score = score;    }    @Override    public String say() {        return super.say() + "score" + score;    }    public void study(){        System.out.println(getName()+"在学习");    }}

子类:

package polyarr;/** * @Auther: qianl * @Date: 2022/10/21 22:09 * @Description: */public class Teacher extends  Person {    private double salary;    public Teacher(String name, int age, double salary) {        super(name, age);        this.salary = salary;    }    public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }    @Override    public String say() {        return super.say() + "salary" + salary;    }    public void teach(){        System.out.println(getName()+"在教书");    }}

结果 : 就是使用instanceof 判断是不是某个子类 然后继续调用其特有方法

package polyarr;/** * @Auther: qianl * @Date: 2022/10/21 22:10 * @Description: */public class PloyArray {    public static void main(String[] args) {        Person[] person1 =new Person[5];        person1[0] = new Person("dio",30);        person1[1] = new Student("student1",30,100);        person1[2] = new Student("student2",30,200);        person1[3] = new Teacher("teacher1",30,10000);        person1[4] = new Teacher("teacher2",22,5000);        for (int i = 0; i < person1.length; i++) {            //动态绑定机制 找方法            System.out.println(person1[i].say());            //输出子类特有方法            if(person1[i] instanceof Student){                ((Student)person1[i]).study();            }else if(person1[i] instanceof Teacher){                ((Teacher)person1[i]).teach();            }else{                continue;//跳过            }        }     /*   dio 30        student1 30 score100.0        student1在学习        student2 30 score200.0        student2在学习        teacher1 30 salary10000.0        teacher1在教书        teacher2 22 salary5000.0        teacher2在教书*/    }}

多态 多态参数

注意点:

1.调用当前类的方法 创建一个当前类的对象 去引用方法

2.父类的方法在子类改写后 是调用父类方法 super.getAnnual();

那么 计算使用的数据还是 子类传输的数据.

//计算年工资public double getAnnual() {return monthlySalary * 12;}

方法中的这个形参指向父类的属性 但是实际参数是使用子类传递的参数.

也是就 方法定义的形参类型 为父类类型 ,实参类型 允许为子类类型

package polyarr;/** * @Auther: qianl * @Date: 2022/10/22 01:05 * @Description: *///获取任何员工对象的年工资,并在main方法中调用该方法.public class TestEmployee {    //工作方法    public void testWork(Employee e) {        //调用子类的特有方法  向下转型        if (e instanceof Manager) {            ((Manager) e).manage();        } else if (e instanceof Worker) {            ((Worker) e).work();        } else {            //父类方法 不做处理            System.out.println("不做处理");        }    }    //获得员工和经理的年工资    public void showEmpAnnal(Employee e) {        System.out.println(e.getAnnual());//调用方法 所以是各个子类的自己的方法.    }    public static void main(String[] args) {        Worker tom = new Worker("tom", 2500);        Manager jeck = new Manager("jeck", 5000, 2000);        //使用当前类的方法?  需要new一个当前类的实例化 才能在当前类中使用当前类的方法.        TestEmployee testEmployee = new TestEmployee();        testEmployee.showEmpAnnal(tom);        testEmployee.showEmpAnnal(jeck);        testEmployee.testWork(tom);        testEmployee.testWork(jeck);    }}//父类class Employee {    private String name;    private double monthlySalary;    public Employee(String name, double monthlySalary) {        this.name = name;        this.monthlySalary = monthlySalary;    }    //计算年工资    public double getAnnual() {        return monthlySalary * 12;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getMonthlySalary() {        return monthlySalary;    }    public void setMonthlySalary(double monthlySalary) {        this.monthlySalary = monthlySalary;    }}class Manager extends Employee {    private double bonus;    public Manager(String name, double monthlySalary, double bonus) {        super(name, monthlySalary);        this.bonus = bonus;    }    @Override    public double getAnnual() {        return super.getAnnual() + bonus;    }    //管理方法    public void manage() {        System.out.println("管理方法....");    }    public double getBonus() {        return bonus;    }    public void setBonus(double bonus) {        this.bonus = bonus;    }}class Worker extends Employee {    public Worker(String name, double monthlySalary) {        super(name, monthlySalary);    }    @Override    public double getAnnual() {        return super.getAnnual();    }    public void work() {        System.out.println("工作方法");    }}

第十章:Object类详解

Object 是类层次结构的跟类,每个类都使用Object作为超类,所以所有对象(数组) 都可以实现这个类的方法.

Modifier and TypeMethod and Description
protected Objectclone()创建并返回此对象的副本。
booleanequals(Object obj)指示一些其他对象是否等于此。
protected voidfinalize()当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。
classgetClass()返回此 Object的运行时类。
inthashCode()返回对象的哈希码值。
voidnotify()唤醒正在等待对象监视器的单个线程。
voidnotifyAll()唤醒正在等待对象监视器的所有线程。
StringtoString()返回对象的字符串表示形式。
voidwait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
voidwait(long timeout)导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。
voidwait(long timeout, int nanos)导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或一定量的实时时间。

1.== 运算符与equals

== 是一个比较运算符

== 判断基本类型 是值相等

== 判断引用类型 是引用相等 地址== 既可以判断基本类型, 也可以判断引用类型

package Object_.equals_;/** * @Auther: qianl * @Date: 2022/10/23 02:18 * @Description: */public class Equals01 {    //== 判断基本类型  是值相等    //== 判断引用类型  是引用相等 地址    //== 既可以判断基本类型, 也可以判断引用类型    public static void main(String[] args) {        A a = new A();        A b = a;        A c = b;        System.out.println(a == b);        System.out.println(a == c);        System.out.println(b == c);        B b1 = new B();        A a1 =b1;        System.out.println(a1 == b1);        int i = 1;        int i1 = 1;        System.out.println(i == i1);        //ture        //true        //ture        //ture        //ture    }}class A{}class B extends A{}

equals方法

只能比较引用类型 只比较地址 所以子类通常都会自行重写equals方法

String equals源码

public boolean equals(Object anObject) {        if (this == anObject) {            return true;        }// 如果当前对象和目标对象是同一个对象 则返回true        if (anObject instanceof String) {            String anotherString = (String)anObject;//当前对象向下转型            int n = value.length;//当前对象长度            if (n == anotherString.value.length) {//如果长度相同                char v2[] = anotherString.value;                int i = 0;                while (n-- != 0) { //然后比较一个一个的字符.                    if (v1[i] != v2[i])                        return false;                    i++;                }                return true;//如果所有字符串相等 返回true            }        }        return false; //如果目标不是字符串 返回false    }

Object equal源码

public boolean equals(Object obj) {        return (this == obj);//判断引用类型 所以是判断地址    }

Integer equal源码

//直接判断值是否相等

public boolean equals(Object obj) {        if (obj instanceof Integer) {            return value == ((Integer)obj).intValue();        }        return false;    }

练习: 注意 == 基本类型就是比较值 == 引用类型 就是比较对象的地址

equals 只有引用类型 比较的是地址

package Object_.equals_;/** * @Auther: qianl * @Date: 2022/10/23 02:18 * @Description: */public class Equals01 {    //== 判断基本类型  是值相等    //== 判断引用类型  是引用相等 地址    //== 既可以判断基本类型, 也可以判断引用类型    public static void main(String[] args) {        Integer integer1 = new Integer(100);        Integer integer2 = new Integer(100);        System.out.println(integer1 == integer2);//都是引用类型 判断地址 false        System.out.println(integer1.equals(integer2));//true 改写了变成 判断值        String s = new String("111");        String s1 = new String("111");        System.out.println(s == s1);// false 不同对象        System.out.println(s.equals(s1));// 比较值 所以是true    }}

equals的重写练习

package Object_.equals_;/** * @Auther: qianl * @Date: 2022/10/23 04:12 * @Description: */public class EqualsOverride {    public static void main(String[] args) {        Person person1 = new Person("jack", 10, "男");        Person person2 = new Person("jack", 10, "男");        System.out.println(person1.equals(person2)); //默认是 == 比较的地址 但是我们要判断地址的同时 比对值    }}class Person{    private String name;    private int age;    private char gender;    @Override    public boolean equals(Object obj) { //披着Object类型的Person类型.编译类型是Object        // 也就是 Object obj = new Person;        if(this == obj){//如果对象相同则true            return true;        }        //类型判断 如果是Person类 就开始判断        if(obj instanceof Person){            Person person = (Person)obj;//向下转型 才能获取到obj的属性 不然就是Object类型            // 全都对 返回true 否则返回false  前一个是String引用类型 比较值 后面两个是基本类型 比较值            return this.name.equals(person.name) && this.age == person.age && this.gender == person.gender;        }        return false;    }    public Person(String name, int age, char gender) {        this.name = name;        this.age = age;        this.gender = gender;    }    //get set方法}

重点: 判断练习1:

总结: 比较方法 是== 还是 equals 没有意义 主要还是

1.看equals 有没有重写(基本数据类型的包装类都是重写过的)2.比较双方是什么类型

1.p1 == p2 p1 与 p2都是引用类型 所以 比较地址 false

2.p1.name.equals(p2.name)使用的是String的比较方法 比较值 所以 true

3.p1.equals(p2)使用的Object的方法 ( == ) 引用类型 所以比较的是地址 false

4,s1.equals(s2)比较方法是 String的方法 比较值 true

5.s1 == s2比较的是引用类型 比较地址 false

注意: 基本数据类型 是忽略小数点.

2.hashCode方法

集合 :Map hashTable

1、提高具有哈希结构的容器的效率

2,两个引用,如果指向的是同一个对象,则哈希值 肯定是一样的

3,两个引用, 如果指向的是不同对象,则哈希值是不一样的

4,哈希值主要根据地址号来的, 不能完全将哈希值等价于地址.

5.案例演示(HashCode_.java):obj.hashCode() [测试: A obj1= new A(); A obj2 = new A(); A obj3 = obj1 ]

6.集合 中 HashCode 需要的话 也会重写.

Hash值 :散列

Hash散列,通过关于键值(key)的函数,将数据映射到内存存储中一个位置来访问。这个过程叫做Hash,这个映射函数称做散列函数,存放记录的数组称做散列表(Hash Table),又叫哈希表。JAVA函数hashCode()即请求对象的哈希值。 (键值对)

映射注意B中唯一的元素也就是 内存存储中 只有唯一一个元素与 散列的值对应

两个非空集合A与B间存在着对应关系f,而且对于A中的每一个元素a,B中总有唯一的一个元素b与它对应,就这种对应为从A到B的映射,记作f:A→B。其中,b称为元素a在映射f下的,记作:b=f(a)。a称为b关于映射f的原像。集合A中所有元素的像的集合称为映射f的值域,记作f(A)。

package Object_.HashCode;/** * @Auther: qianl * @Date: 2022/10/25 00:04 * @Description: */public class HashCode_ {    public static void main(String[] args) {        AA aa = new AA();        AA aa2 = new AA();        AA aa3 = aa;        System.out.println(aa.hashCode());        System.out.println(aa2.hashCode());        System.out.println(aa3.hashCode());        /*356573597   并不是地址 而是映射地址的值        1735600054        356573597*/    }}class AA{}

3.toString方法

默认返回的是全类名 就是包名加类名 + @ + 哈希值 16进制

子类都会重写 也有使用Alt + Ins快捷键 进行重写。

toString源码

public String toString() {        //   全类名  + hashCode()        return getClass().getName() + "@" + Integer.toHexString(hashCode());    }

4.finalize方法

finalize fin- 尖 最终方案

实例中, 是几乎不会用, 因为要尽量避免

对象被回收时,系统自动调用该对象的finalize方法, 之类可以重写该方法,做一些释放资源(内存、数据库链接、打卡的文件等)的操作。 (因为都继承了Object 所以默认调用Object的方法)

当垃圾回收器不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

什么时候对象会被回收: 当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象, 就会使用垃圾回收机制来销毁该对象, 在销毁该对象前,会先调用finalize方法. (来判定?)

垃圾回收机制的调用, 由系统来决定, 也可以通过System.gc() 主动出发垃圾回收机制,

finalize方法Object源码

protected void finalize() throws Throwable { }

案例:

注意,System.gc 不会造成阻塞,而是两个线程, 会接着往下走 而调用的重写的finalize 在被调用就顺延了

程序退出..使用了重写的finalize

package Object_;/** * @Auther: qianl * @Date: 2022/10/26 09:36 * @Description: */public class Finalize_ {    public static void main(String[] args) {        Car car = new Car("奔驰");        car = null; // 没有指向, 这时候 就会回收该对象, 在销毁对象空间前,会调用finalize方法.        //可以在finalize中,写自己需要的业务逻辑代码        //不重写 则自动调用Object的finalize方法,默认处理,        //如果重写就可以实现自己的逻辑        System.gc();        System.out.println("程序退出..");    }}class Car{    private String name;    public Car(String name) {        this.name = name;    }    //默认重写的代码是    @Override    protected void finalize() throws Throwable {        //super.finalize(); 使用的是Object的方法        System.out.println("使用了重写的finalize");    }}

5.debug 断点调试

使用断点调试,可以一步一步看程序的执行过程,

注意: 在断点调试过程中, 是处于运行状态的, 是以对象的运行类型来执行的.

1.在某一行设置断点,调试时,程序运行到这一行会停下, 任何可以一步步往下调试,可以看到各变量当前值, 出错时, 调试到出错代码行便会停止,进行分析从而找到该bug.

2.断点调试是必备技能

3,也能帮助学习java底层代码的执行过程.

注意 f7 (跳入) f8 (跳出) f9 (resume 执行到下一个断点)

以下三个属于方法的

f7 跳入方法内

f8 逐行执行代码

shift+f8 跳出方法

可以通过Console 进行控制台的切换

也可以查看越界等bug问题

设置勾选掉这两个 就能进入源码了 或者使用强制进入 alt+ shift+f7

查看sort等方法的源码:

//双数据透视快速排序DualPivotQuicksort       /**     * Sorts the specified range of the array by Dual-Pivot Quicksort.     *     * @param a the array to be sorted     * @param left the index of the first element, inclusive, to be sorted     * @param right the index of the last element, inclusive, to be sorted     * @param leftmost indicates if this part is the leftmost in the range     */    *通过双数据透视快速排序对数组的指定范围进行排序。*@param a要排序的数组*@param留下了要排序的第一个元素的索引(包括第一个元素)*@param右键是要排序的最后一个元素的索引(含)*@param leftmost表示此部分是否在范围内最左边    //一直追到sort方法.

到下一个断点 可以动态的下断点 , 也就是debug过程中可以动态下下一个断点.

也支持源码中下断点.

如果上一个是源码 下一个断点在main方法中 也能直接到下一个断点. 这样不限制于一个类. 或者一个断点.

创建对象的过程,

package Debug;import java.util.Arrays;/** * @Auther: qianl * @Date: 2022/10/26 20:04 * @Description: */public class debug01 {    public static void main(String[] args) {        //创建对象的过程, 先加载主方法,类信息 test = {Person}        //1. 加载 Person信息        //2. 初始化 2.1 默认初始化, 2.2 显式初始化, 2.3 构造器初始化        //3. 返回对象地址        Person test = new Person("test");        System.out.println(test); //输出类 默认调用toString方法.             }    }}class Person{    public String name;    public Person(String name) {        this.name = name;    }    @Override    public String toString() {        return "Person{" +                "name="" + name + "\"" +                "}";    }}  // System.out,println(test)// 打印类  默认调用toString方法.public static String valueOf(Object obj) {        return (obj == null) ? "null" : obj.toString();    }

零钱通项目:

模拟微信的零钱通

目的: 消费入账 , 消费, 查看明细 ,退出系统等;

化繁为简:

1.先完成显示菜单.

2.实现明细

3.实现入账\消费

4.实现退出的再判断

5.实现入账和消费合理化.

面向过程的方法:

package SmallChanageSys;import java.beans.SimpleBeanInfo;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Scanner;/** * @Auther: qianl * @Date: 2022/10/27 22:43 * @Description: */public class SmallChangeSys {    //先完成显示菜单    public static void main(String[] args) {        //菜单 必须进入 所以必须进入        boolean loop = true; //控制        Scanner scanner = new Scanner(System.in);        String key = "";        //零钱通明细 1. 直接输出字符串 2. 数组 3. 对象MM        String details = "======零钱通明细======";        //完成收益入账 输入金额 并添加总金额 时间        double addMoney = 0;        double sum = 0;        Date date = null;        //日期格式化文本        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//日期格式化.        String consume = "";        double reduceMoney = 0;        String exit = "";        do {            System.out.println("\n======零钱通菜单======");            System.out.println("\t\t\t1 零钱通明细\t\t\t");            System.out.println("\t\t\t2 收益入账\t\t\t");            System.out.println("\t\t\t3 消费\t\t\t");            System.out.println("\t\t\t4 退出系统\t\t\t");            System.out.println("\t\t\t请做出你的选择");            //注意进来以后才开始接受输入            key = scanner.next();            switch (key) {                case "1":                    //零钱通明细方法;                    System.out.println("1 零钱通明细");                    System.out.println(details);                    break;                case "2":                    //收益;                    System.out.println("2 收益入账");                    System.out.println("请输入总金额:");                    addMoney = scanner.nextDouble();                    //应该校验范围 只能增 之类的                    //收益入账 找到正确和不正确的 选少的 再有不正确的进行增if                    //过关斩将,过不了就不能走.                    if(addMoney<=0){                        System.out.println("收益金额 需要大于等于0");                        break;                    }                    sum += addMoney;                    //拼接收益信息                    date = new Date();                    details += "\n收益入帐\t" + addMoney + "\t" + sdf.format(date)                            + "\t" + sum;                    break;                case "3":                    //消费;                    System.out.println("3 消费");                    System.out.println("请输入消费项目:");                    consume = scanner.next();                    //消费同收益                    System.out.println("请输入金额");                    reduceMoney = scanner.nextDouble();                    //应该校验范围 只能增 之类的                    if(reduceMoney <= 0||reduceMoney >= sum){                        System.out.println("消费应该在 0 - "+sum);                        break;                    }                    sum -= reduceMoney;                    //拼接收益信息                    date = new Date();                    details += "\n" + consume + "\t" + reduceMoney + "\t" + sdf.format(date)                            + "\t" + sum;                    break;                case "4":                    //退出系统; while + break 来实现循环.do while实现必须进入.                    System.out.println("4 退出系统");                    //限制 必须输入y/n 否则循环 一段代码完成一种功能 当然也能合起来.                    while (true) {                        System.out.println("你确定要退出吗? y/n");                        exit = scanner.next();                        if ("y".equals(exit) || "n".equals(exit)) {                            break;                        }                    }                    //用户退出while,进行判断                    if (exit.equals("y")) {                        loop = false;                    }                    break;                default:                    System.out.println("选择有误, 请重新选择");            }        } while (loop);        System.out.println("系统已退出");    }}

OOP方式实现:

package SmallChanageSys;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Scanner;/** * @Auther: qianl * @Date: 2022/10/28 07:54 * @Description: //实现各个功能 * */public class SmallChangeSysApp {    public static void main(String[] args) {        new SmallChangeSysOOP().mainMenu();        System.out.println("退出了零钱通");    }}package SmallChanageSys;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Scanner;/** * @Auther: qianl * @Date: 2022/10/28 07:54 * @Description: */public class SmallChangeSysOOP {    //属性    //菜单 必须进入 所以必须进入    boolean loop = true; //控制    Scanner scanner = new Scanner(System.in);    String key = "";    //零钱通明细 1. 直接输出字符串 2. 数组 3. 对象MM    String details = "======零钱通明细======";    //完成收益入账 输入金额 并添加总金额 时间    double addMoney = 0;    double sum = 0;    Date date = null;    //日期格式化文本    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//日期格式化.    String consume = "";    double reduceMoney = 0;    String exit = "";    //显示菜单    public void mainMenu() {        do {            System.out.println("\n======零钱通菜单(OOP)======");            System.out.println("\t\t\t1 零钱通明细\t\t\t");            System.out.println("\t\t\t2 收益入账\t\t\t");            System.out.println("\t\t\t3 消费\t\t\t");            System.out.println("\t\t\t4 退出系统\t\t\t");            System.out.println("\t\t\t请做出你的选择");            //注意进来以后才开始接受输入            key = scanner.next();            switch (key) {                case "1":                    this.detail();                    break;                case "2":                    this.income();                    break;                case "3":                    this.pay();                    break;                case "4":                    this.exit();                    break;                default:                    System.out.println("选择有误, 请重新选择");            }        } while (loop);    }    //显示明细    public void detail() {        System.out.println(details);    }    //完成收益入账    public void income() {        //收益;        System.out.println("2 收益入账");        System.out.println("请输入总金额:");        addMoney = scanner.nextDouble();        //应该校验范围 只能增 之类的        //收益入账 找到正确和不正确的 选少的 再有不正确的进行增if        //过关斩将,过不了就不能走.        if(addMoney<=0){            System.out.println("收益金额 需要大于等于0");//            break;            return;//方法里        }        sum += addMoney;        //拼接收益信息        date = new Date();        details += "\n收益入帐\t" + addMoney + "\t" + sdf.format(date)                + "\t" + sum;//        break;    }    //消费    public void pay(){        //消费;        System.out.println("3 消费");        System.out.println("请输入消费项目:");        consume = scanner.next();        //消费同收益        System.out.println("请输入金额");        reduceMoney = scanner.nextDouble();        //应该校验范围 只能增 之类的        if(reduceMoney <= 0||reduceMoney >= sum){            System.out.println("消费应该在 0 - "+sum);            return;        }        sum -= reduceMoney;        //拼接收益信息        date = new Date();        details += "\n" + consume + "\t" + reduceMoney + "\t" + sdf.format(date)                + "\t" + sum;    }    public void exit(){        //退出系统; while + break 来实现循环.do while实现必须进入.        System.out.println("4 退出系统");        //限制 必须输入y/n 否则循环 一段代码完成一种功能 当然也能合起来.        while (true) {            System.out.println("你确定要退出吗? y/n");            exit = scanner.next();            if ("y".equals(exit) || "n".equals(exit)) {                break;            }        }        //用户退出while,进行判断        if (exit.equals("y")) {            loop = false;        }    }}

本章作业

1.对象冒泡排序

定义一个Person类,{name,age,job} 初始阿虎Person 对象数组,有三个Person对象,并按照age 从大到小排序, 提示 使用 冒泡排序法.

package Work;/** * @Auther: qianl * @Date: 2022/10/28 11:38 * @Description: */public class Person01 {    public static void main(String[] args) {        //根据age从大到小排序        Person person01 = new Person("1", 3, "1");        Person person02 = new Person("2", 5, "1");        Person person03 = new Person("3", 1, "1");        Person[] people = {person01, person02, person03};        Person person;        for (int i = 0; i < people.length - 1; i++) {            for (int j = 0; j < people.length - 1 - i; j++) {                if (people[j].getAge() < people[j + 1].getAge()) {                    person = people[j];                    people[j] = people[j + 1];                    people[j + 1] = person;                }            }        }        for (int i = 0; i < people.length; i++) {            System.out.println(people[i].toString());        }    }}class Person {    private String name;    private int age;    private String job;    public Person() {    }    public Person(String name, int age, String job) {        this.name = name;        this.age = age;        this.job = job;    }    @Override    public String toString() {        return "Person{" +                "name="" + name + "\"" +                ", age=" + age +                ", job="" + job + "\"" +                "}";    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getJob() {        return job;    }    public void setJob(String job) {        this.job = job;    }}

2.各个修饰符的访问权限

修饰符同类同包子类不同包
public
protected×
默认××
private×××

3.父类子类的方法调用.

理解不一样

package Work;/** * @Auther: qianl * @Date: 2022/10/28 19:47 * @Description: */public class HomeWork03 {    public static void main(String[] args) {        Teacher pf01 = new Professor("教授01",50,"教授",30000);        System.out.println(pf01.introduce());        Teacher aspf02 = new AsProfessor("副教授02",40,"副教授",25000);        System.out.println(aspf02.introduce());        Teacher lecturer = new Lecturer("讲师03",25,"讲师",10000);        System.out.println(lecturer.introduce());    }}class Teacher{    private String name;    private int age;    private String post;    private double salary;    public Teacher(String name, int age, String post, double salary) {        this.name = name;        this.age = age;        this.post = post;        this.salary = salary;    }    public Teacher(String name, int age, String post) {        this.name = name;        this.age = age;        this.post = post;    }    public String  introduce(){        return "教师名字: "+ name + "年龄: " +                age + "职称: " + post + "基本工资: " ;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getPost() {        return post;    }    public void setPost(String post) {        this.post = post;    }    public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }}class Professor extends Teacher{    private double salary;    public Professor(String name, int age, String post, double salary) {        super(name, age, post);        this.salary = salary*1.3;    }    @Override    public String introduce() {       return super.introduce() + salary;    }}class AsProfessor extends Teacher{    private double salary;    public AsProfessor(String name, int age, String post, double salary) {        super(name, age, post);        this.salary = salary*1.2;    }    @Override    public String introduce() {        return super.introduce() + salary;    }}class Lecturer extends Teacher{    private double salary;    public Lecturer(String name, int age, String post, double salary) {        super(name, age, post);        this.salary = salary*1.1;    }    @Override    public String introduce() {        return super.introduce()+salary;    }}

4.父类方法,子类重写

最好还是父类使用get set方法 然后manager子类中 重写方法使用get来重写.

package Work;import extend_.improve.Base;/** * @Auther: qianl * @Date: 2022/10/28 22:16 * @Description: */public class EmployeeTest {    public static void main(String[] args) {        OrdinaryEmployees oEmployees = new OrdinaryEmployees("普通员工", 200, 30, 1.0);        System.out.println(oEmployees.printSalary());        Manager manager = new Manager("经理", 300, 30, 1.2,1000);        System.out.println(manager.printSalary());    }}class Employee {    private String name;    private double daySalary;    private double workDay;    private double grade;    private double bones = 0;    public Employee(String name, double daySalary, double workDay, double grade, double bones) {        this.name = name;        this.daySalary = daySalary;        this.workDay = workDay;        this.grade = grade;        this.bones = bones;    }    public Employee(String name, double daySalary, double workDay, double grade) {        this.name = name;        this.daySalary = daySalary;        this.workDay = workDay;        this.grade = grade;    }    public String printSalary() {        return "姓名: " + name + " 日工资: " + (daySalary *workDay* grade + bones);}}class Manager extends Employee{    public Manager(String name, double daySalary, double workDay, double grade, double bones) {        super(name, daySalary, workDay, grade, bones);    }    @Override    public String printSalary() {        return super.printSalary();    }}class OrdinaryEmployees extends Employee{    public OrdinaryEmployees(String name, double daySalary, double workDay, double grade) {        super(name, daySalary, workDay, grade);    }    @Override    public String printSalary() {        return super.printSalary();    }}

5.调用不同构造器.

package Work;/** * @Auther: qianl * @Date: 2022/10/28 23:00 * @Description: */public class HomeWork05 {    public static void main(String[] args) {        Worker job1 = new Worker("工人",3500);        System.out.println(job1.printSal());        Peasant job2 = new Peasant("农民",3500);        System.out.println(job2.printSal());        Waiter job3 = new Waiter("服务员",3500);        System.out.println(job3.printSal());        Teachers t01=new Teachers("教师",3000,30,40);        System.out.println(t01.printSal());        Scientist scientist = new Scientist("科学家", 10000, 30000);        System.out.println(scientist.printSal());    }}class Employees {    private String name;    private double sal;    private int classDay;    private double classSal;    private double bones;    public Employees(String name, double sal) {        this.name = name;        this.sal = sal;    }    public Employees(String name, double sal, int classDay, double classSal) {        this.name = name;        this.sal = sal;        this.classDay = classDay;        this.classSal = classSal;    }    public Employees(String name, double sal, double bones) {        this.name = name;        this.sal = sal;        this.bones = bones;    }    public String printSal() {        return "名字: " + name + "基础工资" + sal;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getSal() {        return sal;    }    public void setSal(double sal) {        this.sal = sal;    }    public int getClassDay() {        return classDay;    }    public void setClassDay(int classDay) {        this.classDay = classDay;    }    public double getClassSal() {        return classSal;    }    public void setClassSal(double classSal) {        this.classSal = classSal;    }    public double getBones() {        return bones;    }    public void setBones(double bones) {        this.bones = bones;    }}class Worker extends Employees {    public Worker(String name, double sal) {        super(name, sal);    }    @Override    public String printSal() {        return super.printSal();    }}class Peasant extends Employees {    public Peasant(String name, double sal) {        super(name, sal);    }    @Override    public String printSal() {        return super.printSal();    }}class Waiter extends Employees{    public Waiter(String name, double sal) {        super(name, sal);    }    @Override    public String printSal() {        return super.printSal();    }}class Teachers extends Employees{    public Teachers(String name, double sal, int classDay, double classSal) {        super(name, sal, classDay, classSal);    }    @Override    public String printSal() {        return "名字: " + getName() + "基础工资" + (getSal()+getClassDay()*getClassSal());    }}class Scientist extends Employees{    public Scientist(String name, double sal, double bones) {        super(name, sal, bones);    }    @Override    public String printSal() {        return "名字: " + getName() + "基础工资" + (getSal()+getBones());    }}

6.super,this练习

Father中 f1() {} 方法中 只能super.name; super.g1(); (虽然name 是默认 但是属于同包 可以调用)

this.id ; this.score; this.f1();

Son中 show() 能super.name; super.id; super.g1(); super.f1();

this.name ; this.g1(); this.show(); 同时 由于this 也是就近原则, 所以可以 this.id; this.f1()

  1. 默认修饰符 同包内 也能访问.
  2. this和super 都可以向上访问 this 从自身开始(就近原则) 向上查找 (会被private截胡) super跳过自身, (然后开始就近原则 一样会被截胡)

7.super this练习2

Demo().test();

​Test 父类构造器

​Demo 子类构造器

​Rose

​Jack

Demo("john").test()

​John

​jack

8.重写 模拟银行存取手续费与次数减免

package Work;import java.lang.reflect.WildcardType;/** * @Auther: qianl * @Date: 2022/10/29 10:42 * @Description: */public class Bank {    public static void main(String[] args) {     /*   CheckingAccount c = new CheckingAccount(1000);        c.deposit(100);        c.deposit(200);        c.withdraw(100);        System.out.println(c.getBalance());*/        SavingsAccount sa = new SavingsAccount(1000);        sa.deposit(100);        sa.deposit(100);        sa.deposit(100);        sa.deposit(100);        System.out.println(sa.getBalance());        sa.withdraw(100);        System.out.println(sa.getBalance());        sa.earnMonthlyInterest();//利息 假设每个月有定时器自动运行        System.out.println(sa.getBalance());// 因为利息方法 会重置count。        sa.deposit(100);//会免手续费        System.out.println(sa.getBalance());        //1309.98        //1409.98    }}class BankAccount {    private double balance;//余额    public BankAccount(double initialBalance) {        this.balance = initialBalance;    }    //存款    public void deposit(double amount) {        balance += amount;    }    //取款    public void withdraw(double amount) {        balance -= amount;    }    public double getBalance() {        return balance;    }    public void setBalance(double balance) {        this.balance = balance;    }}class CheckingAccount extends BankAccount {    public CheckingAccount(double initialBalance) {        super(initialBalance);    }    @Override    public void deposit(double amount) {        //存钱-1块        super.deposit(amount - 1);    }    @Override    public void withdraw(double amount) {        //取钱-1块        super.withdraw(amount + 1);    }}class SavingsAccount extends CheckingAccount {    private int count = 3;    private double rate = 0.01;//利率    public SavingsAccount(double initialBalance) {        super(initialBalance);        count = 3;    }    public void earnMonthlyInterest() {        count = 3;        super.deposit(getBalance() * rate);    }    @Override    public void deposit(double amount) {        if (count > 0) {            super.deposit(amount + 1);        } else {            super.deposit(amount);        }        count--;    }    @Override    public void withdraw(double amount) {        if (count > 0) {            super.withdraw(amount - 1);        } else {            super.withdraw(amount);        }        count--;    }}

9重写equals方法:

package Work;/** * @Auther: qianl * @Date: 2022/10/29 11:19 * @Description: */public class Doctor {    private String name;    private int age;    private String job;    private char gender;    private double sal;    @Override    public boolean equals(Object obj) {        //同一个类直接返回        if(Doctor.super.equals(obj)){            return true;        }        //过关斩将方法        if(!(obj instanceof Doctor)){//不是则返回false            return false;        }        //向下转型,并判断属性.        Doctor doctor = (Doctor) obj;        return this.name.equals(doctor.name) && this.age == doctor.age                && this.job.equals(doctor.job) && this.gender == doctor.gender                && this.sal == doctor.sal;  /*      //判断子类 ,是则向下转型 并判断属性        if (obj instanceof Doctor) {            Doctor doctor = (Doctor) obj;            return this.name.equals(doctor.name) && this.age == doctor.age                && this.job.equals(doctor.job) && this.gender == doctor.gender                && this.sal == doctor.sal;}        return false;*/                }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getJob() {        return job;    }    public void setJob(String job) {        this.job = job;    }    public char getGender() {        return gender;    }    public void setGender(char gender) {        this.gender = gender;    }    public double getSal() {        return sal;    }    public void setSal(double sal) {        this.sal = sal;    }    public Doctor(String name, int age, String job, char gender, double sal) {        this.name = name;        this.age = age;        this.job = job;        this.gender = gender;        this.sal = sal;    }}

10.向上转型和向下转型

package Work;/** * @Auther: qianl * @Date: 2022/10/29 11:39 * @Description: */public class Person02 {    public static void main(String[] args) {        //多态 可以调用父类属性 但是不能调用子类特有属性,方法        //所以只有run 和eat  然后 就近原则.        Person_ s1 = new Student_();        s1.run();        s1.eat();        System.out.println("======");        //向下转型, 直接使用p1 调用特殊方法就匿名向下转型        Person_ p1 = new Student_();        p1.run();        p1.eat();        ((Student_) p1).study();        System.out.println("=====");        //向下转型 可以直接调用子类方法 和父类方法 (就近原则)        Student_ s2 = (Student_)p1;        s2.run();        s2.eat();        s2.study();    }}class Person_{    public void run(){        System.out.println("Person_ run");    }    public void eat(){        System.out.println("Person_ eat");    }}class Student_ extends Person_{    public void run(){        System.out.println("Student_ run");    }    public void study(){        System.out.println("Student_ study");    }}

11.== 和 equals的区别

名字概念用于基本类型用于引用类型
==比较运算符判断属性(内容)判断地址
equals只能用于引用类型no判断地址(hashCode?) 子类重写 可以判断属性是否相等.

12.总结,多态 动态绑定机制

房屋租聘系统(分层模式)

【明确完成功能-->思路分析-->代码实现】

1.需求

一.需求说明能够实现对房屋信息的添加、修改和删除(用数组实现),并能够打印房屋明细表

主要包括:主菜单,新增房源,查找房屋信息,修改房屋信息,删除房屋信息

主菜单

添加房屋信息

查找房屋信息

删除房屋信息

修改房屋信息/4/

房屋列表

退出系统

1, 系统哪些类 , 2, 明确类与类的调用关系

  • 表现层(presentation):用户界面,负责视觉和用户互动
  • 业务层(business):实现业务逻辑
  • 持久层(persistence):提供数据,SQL 语句就放在这一层
  • 数据库(database):保存数据

view 显示 service 业务 domain/model(模型) 数据

还有一个工具类 Utility 类 其中的方法 都是static 的 静态类 都可以使用类.方法()去调用.因为 静态方法 和静态类(比如main方法) 都是在运行时,加载到了类加载器中(方法区的一部分)

主界面 增删改查的操作 房屋类 主入口

2.分析完需求后第一步: 完成House类+toString实现

public class House {    //编号,房主,电话,地址,月租,状态(未出租/已出租)    private int id;    private String name;    private String phone;//电话需要转化    private String address;    private int rent;//租金    private String state;

3.分层模式第二步: 完成mainMenu 显示部分.

public class HouseView {    private boolean loop = true;    private char key = " ";//接受选择    //1可以显示主界面, 2接受用户输入,3调用方法完成操作    public void mainMenu() {        do {            System.out.println("-----------房屋出租系统------------");            System.out.println("           1 新 增 房 源           ");            System.out.println("           2 查 找 房 源           ");            System.out.println("           3 删 除 房 源           ");            System.out.println("           4 修 改 房 屋 信 息           ");            System.out.println("           5 房 屋 列 表           ");            System.out.println("           6 退       出           ");            System.out.println("请做出你的选择");            key = Utility.readChar(key);            switch (key){                case "1":                    System.out.println("-----------新增房源------------");                    break;                case "2":                    System.out.println("-----------查找房源------------");                    break;                case "3":                    System.out.println("-----------删除房源------------");                    break;                case "4":                    System.out.println("-----------修改房屋信息------------");                    break;                case "5":                    System.out.println("-----------房屋列表------------");                    break;                case "6":                    System.out.println("-----------退    出------------");                    loop = false;                    break;                default:                    System.out.println("输入错误,请重新选择:----");                    break;            }        } while (loop);

4.完成房屋列表 等子功能 编写view和service两类.

需求: 并使用数组进行对象管理.

public class HouseService {    private House[] house;//保存房屋对象    public HouseService(int size) {        house = new House[size];        //先创作一个对象        house[0] = new House(1001,"jack","112","海珠区",2000,"未出组");    }    public House[] list(){        return house;    }}//使用数组,设置大小后,数组传入构造器 .      private HouseService houseService = new HouseService(10);//设置数组大小为10;    //编写listHouse() 显示房屋列表    public void listHouse(){        System.out.println("编号\t\t房主\t\t电话\t\t地址\t\t月租\t\t状态(未出租/已出租)");        House[] houses = houseService.list();//得到所以房屋信息        for (int i = 0; i < houses.length; i++) {            if (houses[i]==null){//如果为nll则不输出                break;            }            System.out.println(houses[i]);        }        System.out.println("-----------显示完毕-----------");    }   case "5":                    System.out.println("\r-----------房屋列表------------");                    listHouse();                    break;

单词

单词意思
Encapsulation封装
Account [əˈkaʊnt]账户
password密码
balance[ˈbæləns]平衡;余额
extends继承
puplic小学生
graduate大学毕业生
access接近 权力
theory理论 学说 原理
structure [ˈstrʌktʃə(r)]结构
dynamic动态
binding绑定 结合
equal平等的
monster怪物
master主人
resume简历 (中断后继续)

关键词: