前言

  1. 参考资料:Java学习完整路线
  2. “狂神”老师是我继袁东、小甲鱼、pink后第四位非常喜欢的老师,教学是认真用心的,内容深入浅出,非常棒!
  3. 听了这么多课,感觉自己逐渐摸索到了一些老师的讲课模式。
  4. 九层之台,起于累土,千里之行,始于足下。
  5. 即使再小的帆也能远航。

写 Java 的感受

  1. 不清楚作用域写起代码来,就像迷了路一样。
  2. 大小写十分的敏感,很难受,没法胡写。
  3. 定义变量需要指定数据类型,虽然麻烦,但有好处,不会写迷迷糊糊的代码,让你所学更扎实。
  4. 因为在方法中提前定义了变量的类型,所以即使在输入变量的时候想随便写点什么都不行,直接在变量类型这里就给你 pass 掉了。——方法重载!
  5. args是一个字符串数组的变量名,不是关键字,是arguments的缩写,只是一个默认名,一般都习惯性照写。

聊聊编程这条路

解决大家的疑问

  1. 零基础可以学 Java 吗?必须的。
  2. 学习是为了什么?学习 Java 是为了什么?在学习中提高思想和眼界;做网站,App。
  3. 英语不好能学会吗?天天用,慢慢就掌握了。
  4. 现在学 Java 晚吗?Java 在众多领域都有用武之地,手机App、桌面工具(破解软件),银行系统、支付系统、政企信息系统、大数据平台、网站后台、云管理系统后台、电商系统后台、SaaS云。
  5. Java 和 Python 选择哪个好?编程语言分为两种 Java/C和其他;Python 易上手,体现在拿别人封装的东西来用,假如去深究,也需要时间和精力,如果立志于编程,学C/Java是没错的;实际解决问题需要算法思路,而非语言选择。

课程概述

天数为:朝九晚六的学习时间。

Java全历程210131

如何更高效的学习 Java?

  • 多写,代码、笔记、文章
  • 多练,交流、思维、技能
  • 多分享(知识),多提问,多思考(为什么)
  • 坚持

关于教育和对大家的期望

可上 BOSS直聘 等网站查看工作信息。

预科阶段

博客的重要性

Markdown 语法详解

什么是计算机

硬件及冯诺依曼结构

软件及软件开发

计算机软件可以使计算机按照事先预定好的顺序完成特定的功能。按其功能划分为:

  1. 系统软件:DOS、Windows、Linux、Mac、Android、iOS
  2. 应用软件:Word、Excel、QQ、微信、英雄联盟、王者荣耀

windows常用快捷键

键盘功能键:tab、shift、Ctrl、alt、空格、enter、Windows

键盘快捷键:全选、复制、剪切、粘贴、撤销、保存、删除、运行、打开我的电脑、任务管理器、切换窗口

基本的DOS命令

打开cmd的方式:开始菜单点击、win+r+cmd、shift+右键点击、地址栏输入cmd

常用的DOS命令

#盘符切换
#查看当前目录下的所有文件
#切换目录
#清理屏幕 cls (clear screen)
#退出终端 exit
#查看电脑的ip ipconfig
#打开应用
    calc
    mspaint
    notepad
#ping 命令
    ping www.baidu.com
#文件操作
    md  目录名 #make directory
    rd  目录名
    cd> 文件名
    del 文件名

计算机语言发展史

计算机语言如何变得更易更强?即提高硬件的运行效率提高程序员的开发效率,两者不可兼得。

摩尔定律:每隔18个月,性能便会提升一倍,经过数十年的飞速发展,目前这个定律正在失效中。

机器语言

  • 计算机基本的计算方式基于二进制的方式
  • 二进制:011011100101110111100010011010101111101111
  • 这种代码可直接输入给计算机使用,不经过任何的转换。
十进制012345678910111213141516
二进制0110111001011101111000100110101011110011011110111110000

汇编语言

  • 使用指令代替二进制,解决人类无法读懂机器语言的问题。
  • 目前应用在逆向工程、机器人、病毒等领域。

高级语言

  • 大体上分为:面向过程和面向对象两大类,C语言是典型的面向过程语言;C++、Java 是典型的面向对象语言。
  • 各种高级语言:C、C++、C#、Java、Python、PHP、JavaScript

    • C:同时具有汇编语言和高级语言的特点,C是高级语言的鼻祖,C主要用来写操作系统等底层。
    • C++:把 C 变成一个面向对象的语言。
    • Java:C++--,把 C++ 中一些难的、不好的东西去掉。
    • C#:Bill Gates 说 Java 是迄今为止最好的语言,于是山寨了Java,推出了 C# 并绑定到自己的 Windows 系统上,推出了 .net平台。

入门环境搭建

Java 帝国的诞生

1972年 C 诞生

  1. 贴近硬件,运行极快,效率极高。
  2. 广泛用于操作系统、编译器、数据库、网络系统等。
  3. 难点和问题:指针和内存管理。在编译的时候发现不了问题,在运行的时候出问题。

1982年 C++ 诞生

  1. 面向对象
  2. 兼容C
  3. 图形领域、游戏等
  4. 问题:非常复杂,学习难度大,对程序员不友好。

1995年 Java 初生

  1. 语法有点像C
  2. 没有指针、没有内存管理
  3. 真正的可移植性,编写一次,到处运行(JVM虚拟机)
  4. 面向对象
  5. 类型安全
  6. 高质量的类库
  7. Java 2 标准版(J2SE):去占领桌面

Java 2 移动版(J2ME):去占领手机

Java 2 企业版(J2EE):去占领服务器

Java 的发展

众多公司基于Java开发了巨多的平台、系统、工具:

  • 构建工具:Ant、Maven、Jekins
  • 应用服务器:Tomcat、Jetty、Jboss、Websphere、Webblogic
  • Web 开发:Struts、Spring、Hibernate、MyBatis
  • 开发工具:Eclipse、NetBean、Intellij idea、Jbuilder
  • 2006年:Hadoop(大数据领域)
  • 2008年:Android(安卓手机)

Java 的特性和优势

  1. 简单性
  2. 面向对象
  3. 可移植性
  4. 高性能
  5. 分布式
  6. 动态性
  7. 多线程
  8. 安全性
  9. 健壮性
  10. 使用人多,生态丰富

Java 为什么能够成功?一个人的命运啊,当然要靠自我奋斗,但是也要考虑到历史的行程。

Java 三大版本

Write Once,Run Anywhere

  • JavaSE:标准版(桌面程序、控制台开发……)(Java Standard Edition)
  • JavaME:嵌入式开发(手机、小家电……)(Java Micro Edition)
  • JavaEE:E企业级开发(web端,服务器开发……)(Java Enterprise Edition)

JDK JRE JVM

JDK:Java Development Kit

JRE:Java Runtime Environment

JVM:Java Virtual Machine

image-20210130152338428

安装开发环境

安装 JDK8

  1. 搜索 Oracle JDK8,下载速度极其慢,还需要注册账号
  2. 选择合适的安装目录,例如D:\Environment\java\jdk1.8
  3. 配置环境变量,参考内容7分20秒

    1. 右击我的电脑-->属性-->高级系统设置-->环境变量
    2. 添加 JAVA_HOMEimage-20210201170253097
    3. 配置 Pathimage-20210201170749375
    4. 测试 jdk 是否成功安装配置: java -version

jdk 目录简述

  1. bin 可执行程序目录
  2. include 引入C语言的一些头文件,jdk 是由 C 和 C++ 编写的
  3. jre Java 程序的运行环境
  4. lib Java 开发需要的库文件
  5. src 资源文件 source

卸载 JDK

  1. 通过环境变量,找到 Java 的安装目录,删除
  2. 删除 java_home 相关的
  3. 删除 path 下关于 java 的目录
  4. cmd 内查看 java -version,显示无

HelloWorld 详解

  1. 新建一个文件夹,存放代码
  2. 新建一个 java 文件,后缀名为.java,如 helloworld.java
  3. 编写代码
public class helloworld{
    public static void main(String[] args){
        System.out.print("hello,world!");
    }
}
  1. 编译 javac java文件,会生成一个 class 文件
  2. 运行 class 文件,java class文件,成功!
  3. 注意:类名(class)必须要和文件名一致,且首字母大写。

编译型和解释型

翻译的时机不同,可分为:

  • 编译型(compile):直接翻译全部的内容,效率较高,但是万一有更改,还需要再翻译一次。
  • 解释型():执行一次就需要翻译一次,效率较低(不绝对,效率上可能更高)。

Java 程序运行机制:

image-20210130204630270

使用 IDEA 开发

  • 什么是 IDE(Integrated Development Environment)?

    • 用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。
    • 集成了代码编写、分析、编译、调试等一体化功能服务。
    • Eclipse、IntelliJ IDEA
  • jetbrains:Intellij IDEA 的安装与XX

基础语法学习

注释、标识符、关键字

注释

==书写注释是一个非常好的习惯。==平时写代码一定要注意规范。

注释不但是和别人协作时使用,对于提醒自己也很有作用。

  • 单行注释:// 我是单行注释
  • 多行注释:/* 我是块注释 */
  • 文档注释:/** 可被识别的注释 */

有趣的代码注释

标识符、关键字

Java 所有的组成部分都需要名字,类名、变量名、方法名都被称为标识符。

关键字是语言事先定义的,有特别意义的标识符。java关键字_百度百科

abstract booleanbreakbyte
casecatchcharclass
continuedefaultdodoubleelse
extendsfinalfinallyfloat
for ifimplementsimport
instanceofintinterfacelong
newpackageprivateprotectedpublic
return shortstaticsuper
switch thisthrowthrows
tryvoid while

一个按自己的学习进度填满关键字的表格:

八大基本数据类型byteshortintlongfloatdoublecharboolean
包管理importpackage
流程控制ifelseswitchcasedefaultdowhilebreakcontinue
for
修饰符publicdefaultprotectedprivatestaticfinal
类和方法classreturn
面向对象编程extendsthissuperinstanceof
异常throwthrowstrycatchfinally

标识符注意点

  1. 所有标识符都应该以 ==字母、美元符($)、下划线(_)==开头。
  2. 首字符之后,可以是任意字母、美元符、下划线或数字的任何字符组合。
  3. 不能使用关键字作为变量名或方法名。
  4. 标识符是大小写敏感的。
  5. 可以使用中文命名,但不建议这样去做,也不建议使用拼音。

数据类型

Java 数据类型分为:基本类型和引用类型(类、接口、数组)

强类型语言:要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用,具有安全性高的特点,但速度可能有点慢。

弱类型语言:某一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过现行强制转换。

基本类型(primitive type):8种基本数据类型

byteshortintlongfloatdoublecharboolean
1byte2byte484821bit

1B(byte) = 8b(bit)

1KB = 1024B

1MB=1024KB

1GB=1024MB

1TB=1024GB

字符指计算机中使用的字母、数字、字和符号。

引用类型(reference type): 3 种引用类型

引用类型指的是栈里存放的是指向堆中的地址。

image-20210131001058723

注意:

  1. 整数型 默认为 int,如果使用 long 类型,要在数字后加 L(最好使用大写,因为小写会比较像数字1,不容易分辨)
  2. 浮点型 默认为 double,如果使用 float 类型,要在数字后加 F
  3. 了解每种类型的范围。
  4. String 不是关键字,而是一个类

疑问:Java 中的 char 是什么意思?中文的一个字和英文的一个字母一样吗?

数据类型扩展

实例见 demo02。

整数扩展:二进制(0b),十进制,八进制(0),十六进制(0x)

浮点数扩展: ==最好完全避免使用浮点数进行比较!!==

字符扩展:所有的字符本质还是数字。java 使用 Unicode 编码,范围为 0~65536(U0000~UFFFF),根据数字区查表然后输出字符。

转义字符:t 制表符 、n 换行……

类型转换

由于 Java 是强类型语言,所以在进行运算时,要把不同类型的数据转化为同一类型,然后进行运算。

image-20210131155836943

类型转换语法:(类型)变量名;

强制类型转换:由高到低需要。

自动类型转换:由低到高则无需。

注意:

  1. 不能对布尔值进行转换
  2. 不能把对象类型转换为不相干的类型
  3. 转换的时候可能存在内存溢出或者精度问题

JDK7 新特性:数字之间可以用下划线分割,更好的看清楚数字,比如10_0000_0000。

变量、常量

变量

变量:可以变化的量。变量其实是在内存里开辟了一个空间。

Java 是一种强类型语言,每个变量都必须声明其类型。

Java 变量是程序中最基本的存储单元,包括变量名变量类型作用域

语法:type varName [=value]; //类型、名字、值

注意事项:

  1. 每个变量都要有类型,类型可以是基本类型,也可以是引用类型。
  2. 变量名必须是合法的标识符。
  3. 变量声明是一条完整的语句,必须以分号结束。
  4. 为保证程序的可读性,不要在一行定义多个变量。

变量作用域(待学习)

  • 类变量:需要加个关键字 static,可以直接使用。
  • 实例变量:没有关键词 static,在方法外类里,从属于对象的。无须初始化值。使用麻烦,需要 new 对象。默认值数字类为0、0.0 Boolean 默认为false,除了8个基本类型,其他都是null。
  • 局部变量:在方法里的变量,必须声明和初始化值。(类里面可以有方法和属性,main就是一种方法)

常量

常量(constant):initialize 后不能再改变值!不会变动的值。可理解为一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。

常量名一般使用全大写。

修饰符不存在先后顺序。

final double PI=3.14;

变量的命名规范

  1. 所有的变量、方法、类名,要能见名知意
  2. 类变量:首字母小写和驼峰原则:monthSalary
  3. 局部变量:首字母小写和驼峰原则
  4. 常量:大写字母和下划线(单词较多的话使用下划线分隔):MAX_VALUE
  5. 类名:首字母大写和驼峰原则:ManGoodMan
  6. 方法名:首字母小写和驼峰原则:run()runRun()

运算符

Java 语言支持的运算符:

  • 算术运算符:+ - * / % ++ --
  • 赋值运算符:=
  • 关系运算符:> < >= <= == != instanceof
  • 逻辑运算符:&& || !
  • 位运算符(了解即可):& | ^ ~ >> << >>>
  • 条件运算符(偷懒):? :
  • 扩展赋值运算符(偷懒):+= -= *= /=

一元运算符:只操作一个数;二元操作符:操作两个数;三元运算符:操作3个数。

a++ 与 ++a

image-20210131172648598

与 或 非

public class Demo04 {
    public static void main(String[] args) {
        boolean a = true;
        boolean b=false;
        System.out.println("a&&b:"+(a&&b));// 逻辑与运算,两者都为真才为真。
        //短路运算,当发现第一个为假时,直接得出结果,不再往后运算。
        System.out.println(a||b);
        System.out.println(!a);
        System.out.println(!b);

        // 短路运算测试
        int c = 5;
        boolean d = (c<4)&&(c++<10);
        System.out.println(d);
        System.out.println(c);// c的结果还是5,说明 c++并未执行。
    }
}

位运算

/*
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~B = 1111 0010

*/
        //最快计算2的3次方的方法,位运算效率极高。
        /*
        * 1 0000 0001
        * 2 0000 0010
        * 3 0000 0011
        * 4 0000 0100
        * 5 0000 0101
        * 8 0000 1000
        * 16 0001 0000
        * */
        System.out.println(2<<3); // 左移1位相当于把数字乘以2
        System.out.println(16>>2);// 右移1位相当于把数字除以2

字符串连接符和三元运算符

字符串连接符,会把后面的类型都转为字符串输出。

x ? y : z; //如果x = true, 则结果为y,否则结果为z

运算符优先级

用括号就完事了。

包机制、JavaDoc

包机制

包机制:为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。(包的本质就是个文件夹)

包语句语法格式:package pkg1 [. pkg2 [.pkg3..]];

一般利用公司域名倒置作为包名:com.baidu.www

为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包,使用import即可完成此功能。

导入包:import package1.*;

阿里巴巴开发手册

JavaDoc

JavaDoc:用来生成自己的 API 文档。

可写类注释或者方法注释。

参数信息:

  • @author 作者名
  • @version 版本号
  • @since 指明最早使用的jdk版本
  • @param 参数名
  • @return 返回值情况
  • @throws 异常抛出情况

流程控制学习

用户交互 Scanner

Java 给我们提供了一个工具类(Java.util.Scanner (Java5新特性)),让我们可以获取用户的输入,实现程序与人的交互。

基本语法:Scanner s = new Scanner(System.in);

通过 Scanner 类的 next()nextLine() 方法获取输入的字符串,在读取前一般需要使用 hasNext() hasNextLine()判断是否还有输入的数据。

import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
        // 创建一个扫描器对象,用于接收键盘数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("使用next方法接收:");
        // 判断用户有没有输入字符串
        if(scanner.hasNext()==true){
            // 使用next方式接收
            String str = scanner.next();
            System.out.println("输出的内容为:"+str);
        }
        
        scanner.close(); // 凡是属于 io 流的类,一定要用完就关,不然会一直占用资源。
    }
}

next():

  1. 一定要读取到有效字符后才可以结束输入。
  2. 对遇到有效字符之前的空白,会总动将其去除。
  3. 只有得到有效字符后才将其后面输入的空白作为分隔符或结束符。
  4. 此方法不能得到带有空格的字符串。

nextLine():

  1. 以 enter 为结束符,此方法返回的是输入回车之前的所有字符。
  2. 可以获得空白。

顺序结构

Java 的基本结构就是顺序结构,从上到下一句一句执行。顺序结构是最简单的算法结构,是任何一个算法都离不开的一种基本算法结构。

不要忘记顺序结构也是一个结构!

选择结构

if 单选择结构

if (Boolean expression){
    // 如果 布尔表达式 为 true 将执行的语句
}

if 双选择结构

if (Boolean expression){
    // 如果 布尔表达式 为true将执行的语句。
}else{
    // 如果 布尔表达式 为false 将执行的语句。
}

if 多选择结构

if (Boolean expression 1){
    // 如果 布尔表达式1 为 true 将执行的语句。
}else if (Boolean expression 2){
    // 如果 布尔表达式2 为 true 将执行的语句。
}else if (Boolean Expression 3){
    // 如果 布尔表达式3 为 true 将执行的语句。
}else{
    // 如果 以上表达式 都不为 true 执行的语句。
}

switch 多选择结构

Switch Case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

switch (expression){
    case value:
        // 语句
        break;//可选
    case value:
        // 语句
        break;//可选
    // 可以有任意数量的 Case 语句
    default: // 可选
        // 语句
}

Switch 语句中的变量类型可以是:

  • byte、short、int 或 char
  • 从 Java7 开始,Switch 支持 String(字符串)类型了。// 为什么支持字符串,因为在编译的时候,编译器将它转为了 hashCode 来比较。
  • Case 标签必须为字符串常量字面量?(疑问,这是什么意思?)

Switch 穿透:

反编译(Decompiled):

循环结构

while 循环

while ( boolean expression){
    // 循环内容
}
  • 只要 布尔表达式 为 true ,循环就会一直执行下去。
  • ==大多数情况会让循环停止下来的,我们需要一个让表达式失效的方式来结束循环;==少部分情况需要循环一直执行,比如服务器的请求响应 监听等。
  • 正常业务编程中应尽可能避免死循环,会影响程序性能或造成程序卡死崩溃。

do...while 循环

do {
    //代码语句
}while (boolean expression);
  • 与 while 循环类似,但有时我们需要 “即使不满足条件,也要执行一次!”
  • while 先判断后执行,而 do while 是先执行后判断,所以会至少执行一次。

for 循环(!important)

虽然 所有循环结构 都可以用 while 或者 do……while 表示,但 Java 提供了另一种语句“for循环”,使一些循环结构变得更加简单。

  • ==for 循环 是支持迭代循环的一种通用结构,是最有效、最灵活的循环结构。==
  • for 循环 的执行次数是在执行前就确定的。
  for (初始化;Boolean expression;更新){
      // 代码语句
  }
// while 和 for 循环的对比  
public class ForDemo01 {
     public static void main(String[] args) {
         int a = 1;// 初始化条件
 
         while (a<=10){ // 条件判断
             System.out.println(a);// 循环体
             a+=2;// 迭代
         }
         System.out.println("=======while循环结束!=======");
 
         for(int i=1;i<=10;i+=2){ //初始值、条件判断、迭代
             System.out.println(i); // 循环体
         }
         System.out.println("=======for循环结束!=======");
     }
 
 }

关于 “for 循环”的几点说明:

  1. 最先执行初始化步骤,可以声明一种类型。但可初始化一个或多个“循环控制变量”,也可以是空语句。
  2. 然后检测布尔表达式的值,如果为true,循环体执行;如果为false,循环体终止,开始执行循环体后面的语句。
  3. 执行一次循环后,更新“循环控制变量(迭代因子控制循环变量的增减)“。
  4. 再次检测 布尔表达式 ,循环执行上面的过程。
  5. for 循环的死循环写法:

    for ( ; ; ){ //for 的死循环
        //代码语句
    }

关于“for 循环”的练习:

  1. 计算 0 到 100 之间的奇数和偶数的和。奇数的和+偶数的和
  2. 用 while 或 for 循环输出1到1000之间能被5整除的数,并且每行输出3个
  3. 打印99乘法表。

独立做作业的成果(开心):

public class For99Multi {
    public static void main(String[] args) {
        // 打印99乘法表
        // 1. 行使用 i 表示,列使用 j 表示。
        // 2. 行先循环9遍,确定9行;
        // 3. 列嵌套循环,每一行内当列=行号时,停止循环。
        // 4. 调整样式:加个间隔符,每次行号=列号的时候,换行。
        for (int i = 1; i <= 9; i++) { //打印9行
            for(int j = 1; j<=i;j++){  //每一行打印的个数等于行号时,停止。
                System.out.print(j+"×"+i+"="+(i*j)+"\t");
                if(j==i){
                    System.out.println();
                }
            }
        }
    }

image-20210202164125746

增强型 for 循环(Java5 引入)

for (声明语句:表达式){
    // 代码语句
}
  • 暂时了解即可。
  • 主要用于数组或集合,用来简化 for 循环的。
  • 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
  • 表达式:表达式是要访问的数组名,或者是返回值为数组的方法。

break and continue

break 用于强行退出循环,不执行循环中剩余的语句。

continue 用于终止某次循环过程,接着进行下一次是否执行循环的判定。(碰到它直接跳回到循环判定那里,进行判定)

流程控制练习题

打印一个三角形(triangle)


方法详解

什么是方法?

System.out.println(); // 类.对象.方法

Java 方法是语句的集合,它们在一起执行一个功能:

  • 方法是解决一类问题的步骤的有序组合。
  • 方法包含于类和对象中。
  • 方法在程序中被创建,在其他地方被引用。
  • 方法的本意是功能块,设计方法的时候,最好保持方法的原子性(一个方法只完成一个功能)
  • 比如常见的加法,可以设定一个加法方法,直接让几个数相加。

方法的定义

Java 的方法 类似于 其他语言的函数,是一段用来完成特定功能的代码片段

一般情况下,定义一个方法(方法头+方法体)包含以下语法:

  1. 修饰符:可选的。告诉编译器如何调用该方法。定义了该方法的访问类型。
  2. 返回值类型:方法有可能会返回值,returnValueType 是方法返回值的数据类型,有些方法没有返回值,这种情况下,使用关键字 void表示。
  3. 方法名:小写和驼峰命名,方法名和参数表共同构成方法签名。
  4. 参数类型:可选的。参数像是一个占位符,当方法被调用时,传递值给参数,这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数

    • 形式参数:在方法被调用时用于接收外界输入的数据。
    • 实参:调用方法时实际传给方法的数据。
  5. 方法体:包含具体的语句,定义该方法的功能。
  6. 返回值:return 还有终止方法的意思。
修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

方法的调用

调用方法:对象名.方法名(实参列表)

根据方法是否返回值有两种调用方法的方式:

  1. 当方法返回一个值的时候,方法调用通常被当做一个值。如int larger = max(30,40);
  2. 当方法返回值是 void 时,方法调用一定是一条语句。如System.out.println("Hello,world!")

课后拓展:值传递(Java)和引入传递。

方法的重载

重载就是在一个类中,有相同的函数名称,但形参不同的函数。规则:

1. 方法名称必须相同
2. 参数列表(个数、类型、排列顺序)必须不同
3. 方法的返回类型可以相同也可以不同,但仅返回类型不同不足以成为方法的重载

方法名称相同时,编译器会根据调用方法的参数个数、类型、顺序去匹配对应的方法,如果匹配失败,则报错。

命令行传递参数

有时你希望程序在运行时,再传递给它消息,这就要靠传递命令行参数给main()函数实现。(扩展知识)

可变参数

JDK1.5 开始,Java 支持传递同类型的可变参数(不定项参数)给一个方法。

在方法声明中,在指定参数类型后加一个省略号…即可,注意一个方法中只能指定一个可变参数,它必须是方法的最后一个参数(任何普通的参数必须在它之前声明)。

递归

A 方法调用 B 方法,很容易理解,但是 A 方法调用 A 方法,自己调用自己,就是递归(recursion)。

递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。

递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。

递归的能力在于用有限的语句来定义对象的无限集合。

如果递归的深度太深,会影响机器的性能。

递归结构包括两个部分:

- 递归头:什么时候不调用自身方法。如果没有头,讲陷入死循环。
- 递归体:什么时候需要调用自身方法。

方法练习题

写一个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。

  • 写4个方法:加减乘除
  • 利用循环+switch进行用户交互
  • 传递需要操作的两个数
  • 输出结果

练习这个发现了无数的问题:

  1. Scanner 使用不太娴熟,不过可以解决。
  2. Switch 使用不太娴熟
  3. 循环使用不太娴熟。
  4. 变量获取到了,到下一个语句中变量又没有了,实在头疼!——这是最大的问题!

数组详解

什么是数组

  • 数组是相同类型数据的有序集合。
  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。
  • 每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。

数组的声明和创建

首先,必须声明数组变量,才能在程序中使用数组。

声明语法如下:

dataType[] arrayRefVar; 这是首选的方法
dataType arrayRefVar[]; 这是次选方法,C 和 C++ 中使用这个方法

Java 语言使用 new 操作符来创建数组,语法如下:

dataType[] arrayRefVar = new dataType[arraySize];
int[] nums = new int[10];// 实例

数组元素可以通过索引来访问,数组索引从 0 开始。

获取数组长度可使用:arrays.length

整体示例:

public class Demo01 {
    // 变量的类型 变量的名字 = 变量的值 ,数组与此类似。
    public static void main(String[] args) {
        int[] nums; // 1. 声明一个数组
        /*int nums[];// 另一种声明方式 C 和 C++ 风格*/
        nums = new int[10];// 2. 创建一个数组
        /*int[] nums = new int[10]; // 声明+创建*/

        // 3. 给数组元素赋值
        nums[0] = 1;
        nums[1] = 2;
        nums[2] = 3;
        nums[3] = 4;
        nums[4] = 5;
        nums[5] = 6;
        nums[6] = 7;
        nums[7] = 8;
        nums[8] = 9;
        nums[9] = 10;

        // 通过数组索引输出数组元素
        System.out.println(nums[0]);
        System.out.println(nums[9]);

        // 计算所有元素的和
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum = sum + nums[i];
        }
        System.out.println("总和为:"+sum);
    }
}

数组的三种初始化

  1. 静态初始化:声明+创建+赋值,如:int[] a = {1,2,3,4,5,6}
  2. 动态初始化:包含默认初始化,声明+创建空间,后赋值,如:int[] b = new int[10]; b[0]=1;b[1]=2;...b[9]=10;
  3. 默认初始化:数组是引用类型,它的元素相当于类的实例变量(不懂这5个字的意思),因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。——整句话理解了。

数组的内存分析及下标越界异常

image-20210203170301073

image-20210203164434305

数组的四个基本特点

  1. 其长度是确定的,不可变的。一旦被创建,大小不可变!
  2. 其元素必须是相同类型。不允许出现混合类型。
  3. 其元素可以是任何数据类型,包括基本类型和引用类型(类、数组、接口)。
  4. 数组变量属于引用类型,数组也可以看作对象,数组中的每个元素相当于该对象的成员变量。(数组本身就是对象,Java 中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。)

数组的使用

  1. 普通的 for 循环
  2. 增强型 for 循环(for-each):for(int array:arrays){System.out.println(array)}
  3. 数组作为方法入参
  4. 数组作为返回值

二维数组

arr[][]是一个二维数组;a[0] 是一个一维数组;

image-20210204170840905

public class MultiArray {
    // 二维数组
    public static void main(String[] args) {
        int[][] a = {{1,2},{2,3},{3,4},{4,5}};
        System.out.println(a[0][1]);
    // 取出二维数组的每个元素
        for (int i = 0; i < a.length; i++) {
            for(int j = 0;j<a[i].length;j++){
                System.out.println(a[i][j]);
            }

        }
    }
    
}

Arrays 类讲解

Java 公司为了让我们更好的操作 数组 ,特地给我们写好了一个类,叫做 Arrays !

在编辑器内 import Arrays 类,然后点击 Structure 或者直接在面包屑导航栏上,查询其所包含的方法,需要查看帮助文档来理解方法的作用以及如何使用。

Arrays 类中的方法都是 static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用(不用,不是不能)使用对象来调用。

自己写的 toString方法:

    // 代码还可以优化
    public static void printArray(int[]array){ // 待办:方法返回值与返回值类型的问题需要搞清楚。
        for (int i = 0; i < array.length; i++) {
            if(i==0){
                System.out.print("["+array[0]+","+" ");
            }else if(i==array.length-1){
                System.out.print(array[i]+"]");
            }else {
                System.out.print(array[i] + ", ");
            }
        }

冒泡排序

总共有八大排序算法,冒泡排序是最为出名的排序算法(之一)!

详见 没有人比我更懂“冒泡排序”!

稀疏数组

将数组进行压缩和还原。

面向对象编程

什么是面向对象

面向对象编程,Object-Oriented Programming, 简称 OOP ,它的本质就是:==以类的方式组织代码,以对象的方式封装数据。==

三大特性:封装、继承、多态!

从认识论角度考虑是:先有对象后有类。(对象是具体的事物;类是对象的抽象)

从代码运行角度考虑是:先有类后有对象,类是对象的模板。(程序一般是先设计一个类,再 new 出好多对象)

面向过程思想:线性

  • 步骤清晰简单,第一步做什么,第二步做什么....
  • 面向过程适合处理一些较为简单的问题

面向对象思想:

  • 物以类聚,分类的思维模式。思考问题首先会考虑解决问题需要哪些分类,然后对这些分类进行单独思考,最后才对某个分类下的细节进行面向过程的思索。
  • 面向对象适合处理复杂的问题,需要多人协作的问题。

对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但具体到微观操作,仍然需要面向过程的思路去处理。

回顾方法的定义、调用

重温一下方法定义

return 表示方法已经结束了,返回一个结果,可以是空也可以是其他。

静态方法与非静态方法

静态方法:使用 static 修饰符的方法,可以之直接使用Class.methodName()来调用。

非静态方法:必须要将类实例化(new 一个对象才能用),Object.methodName()。实际开发都是这样用的!

static 修饰符定义的方法是和类一起加载的,而非静态方法是在类实例化后才存在的。

形参与实参

实际参数和形式参数的类型要对应。

值传递和引用传递

完全晕了,对象和内存不懂,所以晕了!

public class Demo01 {
    public static void main(String[] args) {
        // 值传递和引用传递
        int a =1; // a 是一个变量名
        System.out.println(a);

        change(a);

        System.out.println("change 过后a="+a);
    }
    public static int change(int a){ // a是一个形参,这个方法没有返回值
        a = 10; // 方法执行完,里面的a确实变成了10,可用debug查看
        return a; // 即使return一个值,上面结果还是不变!
    }
}

类与对象

类是一种抽象的数据类型,它是对某一类事物的整体描述,但并不代表某一个具体的事物。比如:动物、植物、手机、电脑,人,宠物,汽车等等,都是用来描述一类具体事物应该具备的特点(属性)和行为(方法)。

对象是抽象概念的具体实例。比如:张三就是一个人的实例,张三家的旺财就是狗的一个实例。能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。

创建和初始化对象

使用 new关键字创建对象。

使用 new 关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及调用类中的构造器

一个项目应该只存在一个 main 方法,不要在每个类里都写上 main 方法,之前这样写,只是为了方便调用。

构造器(Constructor)详解(难点)

构造器到底是什么?(个人思考)

当使用Class()的时候,其实是调用了一个方法,但是这个类里面其实什么都没有,属性没写方法也没写。这时候,其实编译器默认给了这个空白的类一个方法,这个方法就叫做构造方法。

它有两个特点:1.方法名和类名相同;2.没有返回类型,也不能写void

构造方法或者说构造器,和普通的方法是不同的,就体现在上述两个特点之上。

——2021年2月10日,复习理解。

类中的构造器也称为构造方法,是在创建对象时必须要调用的,并且构造器有两个特点:

  1. 必须和类的名字相同;
  2. 必须没有返回类型,也不能写 void。

空白类的编译文件,如图所示:image-20210206215655344

构造器的作用:

  1. 使用 new 关键字,其实是在调用构造方法(无参的或有参的)。
  2. 用来初始化值。
  3. 有参,无参。(定义有参构造之后,如果想使用无参构造,必须显式定义一个无参构造。(不写有参的话编译器会给你一个无参构造))
  4. alt + insert 快捷键,快速生成构造器!

创建对象的内存分析

public class Application { // 加载一个 Application 类
    public static void main(String[] args) { // 在栈中加入 main()方法

        Pet dog = new Pet(); // 堆中方法区加载一个 Pet 类,在堆中初始化一个 Pet 对象,在栈中创建引用指向堆中的对象。
        dog.name ="旺财"; // 赋值 
        dog.age = 3;
        dog.shout();
        
        Pet cat = new Pet();

        System.out.println(dog.name);
        System.out.println(dog.age);
    }
}

public class Pet {
   public String name;
   public int age;

    public void shout(){
        System.out.println("叫了一声~");
    }
}

image-20210207142658195

对象的属性

或称字段(field)或称成员变量,属性会默认初始化:

数字0 或0.00
charu0000
booleanfalse
引用null

封装详解

封装,字面意思,比如电视机,看电视的时候遥控器换台就行了,不需要去操作显像管、信号器什么的。

程序设计要追求“高内聚、低耦合”,“高内聚”指的是类内部数据操作细节自己完成,不允许外部干涉;“低耦合”指的是仅暴露少量的方法给外部使用。

封装是指一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法。同时,它也是一种防止外界调用端,去访问对象内部实现细节的手段,这个手段是由编程语言本身来提供的。

属性私有,get/set方法

快捷键:alt+insert 快速生成 get/set 方法

快捷操作:a.getName().sout快速打印输出

public class Student {
    // 属性私有,更安全,隐藏细节
    private String name;
    private int id;
    private char sex;
    private int age;
    
    // get 获得这个数据
    public String getName(){
        return this.name;
    }
    // set 方法,设置这个属性的值。
    public void setName(String name){
        this.name = name;
    }
    // 可以进行一些数据检查,避免传进去一些离谱的数据,破坏这个系统
    public int getAge(int age){
        return age;
    }
    public void setAge(int age){
        if (age>0||age<120){
            this.age = age;
        }else{
            this.age = 3;
        }
    }
}

封装的意义:

  1. 提高程序的安全性,保护数据;
  2. 隐藏代码的实现细节;
  3. 统一接口;
  4. 增加系统的可维护性。

什么是继承(Inheritance)

继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。(类的复用;增加了类之间的耦合性)

​ — Java 继承 | 菜鸟教程 (runoob.com)

在令子类继承父类的同时,可以重新定义某些属性,并重写某些方法(即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。)另外,为子类追加新的属性和方法也是常见的做法。

关键字:extands (扩展),子类是父类的扩展。

Java 中只有单继承,没有多继承(一个儿子只能有一个爸爸,一个爸爸可以有多个儿子)。

语法:

public class Teacher extends Person{
    
}
public class Student extends Person{
    
}
// 1.子类可以使用父类的属性和方法,也可以重新定义属性和重写方法(覆盖父类的)或追加新的属性和方法。
// 2.私有的东西,无法被继承。private 的就不能被继承。属性一般都是私有的,然后给你方法(set/get)让你操作。
// 3.protected 受保护的。

四个修饰符:public protected default private ,私有的东西无法被继承。

快捷键:Ctrl + h 打开继承树。

在 Java 中,所有的类默认都继承 Object 类。

Super 详解

this 代表当前类,super 代表当前类的父类。

对于构造器来说,当 new 一个子类对象的时候,子类会去调用父类的构造器。

super:在代码中很好理解的。

  1. super 调用父类的构造方法,必须在构造方法的第一行。
  2. super 只能出现在子类的方法或者构造方法中。
  3. super 和 this 不能同时调用构造方法。

VS this:

  1. 代表的对象不同:this 是本身调用者这个对象,super 代表父类对象的应用。
  2. 前提:this 没有继承也可以使用;super 只能在继承条件才能使用。
  3. 构造方法:this() 调用本类的构造;super() 调用父类的构造!

方法重写(Override)

需要有继承关系,子类重写父类的方法:

  1. 方法名必须相同(快捷键 alt + insert,选择 override)
  2. 参数列表必须相同
  3. 修饰符:重写时范围可扩大(public>protected>default>private)
  4. 抛出的异常:范围可以被缩小,但不能扩大。(ClassNotFoundException-->Exception)

为什么需要重写:父类的功能,子类不一定需要,或者不一定满足。

什么是多态(Polymorphism)

多态指 为不同数据类型的实体提供统一的接口,或使用一个单一的符号来表示多个不同的类型。

同一方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向的引用类型不确定。比如 Student s1 = new Student(); Person s2 = new Student(); Object s3 = new Student(); 同一个对象可以是多种类型,Student类,Person类,Object类。

对象能执行哪些方法,主要是看左边的引用类型。(父类型对象想调用只在子类型中存在的方法,需要强制转换类型,转换成子类型再调用。)

多态存在的条件:

  1. 有继承关系。
  2. 子类重写父类方法。
  3. 父类引用指向子类对象。Father f1=new Son();

多态的注意事项:

  1. 多态是方法的多态,属性没有多态。
  2. 父类和子类的类型转换,需要两者之间有联系。ClassCastException

不能被重写的方法:

  1. static 方法属于类,不属于某个实例。
  2. final 常量,在常量池里。
  3. private 方法,无法重写。

instanceof

instanceof 可以判断一个对象是什么类型。

x instanceof y 能否编译通过,主要看 X 和 Y 有没有父子关系,不然的话在编译阶段就通不过。

Object object = new Student();
System.out.println(object instanceof Student);// ture
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false

类型转换

低——>高(子类转换为父类):自动转换

高——>低(父类转换为子类):强制转换

方便方法的调用,减少重复的代码,比如父类想用子类的方法,只需要转换一下类型就可以,不用再去写代码了。

static 关键字详解

static 修饰的属性和方法,可以直接使用Class.attribute 来调用,因此也被称为类变量。

匿名代码块:每次 new 对象都会执行

静态代码块:只执行一次

构造方法:每次 new 对象都会执行

静态导入包:直接把包里的一个方法调用进来。

抽象类

abstract 修饰符可以用来修饰方法,也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。

  1. 抽象类中可以没有抽象方法,也可以写普通方法,但抽象方法一定要在抽象类中。
  2. 抽象类不能使用 new 关键字来创建对象,它是用来让子类继承的。
  3. 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。

我只写个框架,要是有人能帮我把这个方法实现了就好了,哈哈,我喜欢这个!

子类要继承抽象类,就必须要实现它没有实现的抽象方法,否则该子类也要声明为抽象类。

接口的定义与实现

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是……则必须能……”的思想。

如果你是鸟人,则必须能飞;如果你是汽车,则必须能跑;如果你是好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。

声明类的关键字是 class,声明接口的关键字是 interface。

  • 接口里所有定义的方法都是公开的(public),抽象的(abstract),默认都给你写了,不用你自己写!
  • 接口里所有定义的属性都是:public static final
  • 接口不能被实例化,接口中没有构造方法。
  • 接口可以多继承,抽象类只能单继承。
  • 接口都需要有一个实现类,来实现接口的方法:public class UserServiceImpl implements UserService,timeService{}//利用接口实现多继承

普通类:只有具体实现。

抽象类:具体实现和规范(抽象方法)都有。

接口:只有规范!自己无法写方法!专业的约束!

约束和实现分离:面向接口编程~

OO的精髓,就是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。

内部类(待理解)

在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,而A类相对于B类来说就是外部类了。

  1. 成员内部类:可以获得外部类的私有属性和私有方法
  2. 静态内部类:
  3. 局部内部类:在方法里定义一个类
  4. 匿名内部类

异常机制

什么是异常

异常指程序运行中出现的不期而至的各种情况,如:文件找不到、网络连接失败、非法参数等。这些异常,需要我们让写出的程序作出合理的处理。

实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求:你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的;程序在跑着,内存或硬盘可能满了等等。

简单分类:

  • 检查性异常:用户错误或问题引起的异常,这是程序员无法预见的。例如打开一个不存在的文件,异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常:可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误:错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们再编译也检查不到。

异常体系结构

Java 把异常当做对象来处理,定义一个基类 java.lang.Throwable 作为所有异常的超类。

在 Java API 中已经定义了许多异常类,这些异常类分为两大类:错误和异常。

  • Error 类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
  • Exception 分支中重要的子分类 RuntimeException
  • Error 通常是灾难性的致命错误,是程序无法控制和处理的,当出现时,Java 虚拟机(JVM)会终止进程;Exception 通常情况下是可以被程序处理的,并且在程序中应尽可能的去处理这些异常。

image-20210212120836354

Java异常处理机制

异常处理的五个关键字:try catch finally throw throws

捕获异常:Ctrl + alt + T,快捷键自动添加

    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        try{
            System.out.println(a/b);
        }catch (ArithmeticException e){//想要捕获的异常类型
            System.out.println("程序出现异常,请检查除数是否为0");
        }finally{
            System.out.println("终究会被执行!");
        }
    }

抛出异常:主动抛出异常。

new test().test(1,0)
public void test(int a,int b){
    if (b==0){ // throw throws 两者不同
    throw new ArithmeticException();//主动抛出异常,一般在方法中使用
    }
    System.out.println(a/b);
}

自定义异常

使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常,只需继承 Exception 类即可。

在程序中使用自定义异常类,大体可分为以下几个步骤:

  1. 创建自定义异常类
  2. 在方法中通过 throw 关键字抛出异常对象
  3. 如果在当前抛出异常的方法中处理异常,可以使用 try-catch 语句捕获并处理;否则在方法的声明处通过 throws 关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  4. 在出现异常方法的调用者中捕获并处理异常。

经验小结

  • 处理运行异常时,采用逻辑去合理规避同时辅助 try-catch 处理。
  • 在多重 catch 块后面,可以加一个 catch(Exception)来处理可能会被遗漏的异常。
  • 对于不确定的代码,也可以加上 try-catch,处理潜在的异常。
  • 尽量去处理异常,切忌只是简单地调用 printStackTrace() 去打印输出。
  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定。
  • 尽量添加 finally 语句块去释放占用的资源。

JavaSE 总结

JavaSE

如果觉得我的文章对你有用,请随意赞赏