Java基础总结(初到中)

计算机组成部分

概述

计算机包括硬件(hardware)和软件(soxware)两部分。一般来说,硬件包括计算机中可以看得见的物理部分,而软件提供看不见的指令,这些指令控制硬件并且使得硬件完成特定的任务。学习一种程序设计语言,并不一定要了解计算机硬件知识,但是如果你了解一些硬件知识的话,它的确可以帮助你更好地理解程序中指令对于计算机及其组成部分的功效
在这里插入图片描述

  • 一台计算机是由一下几个主要的硬件组成构成的:
    中央处理器(Center Processing Unit,CPU)
    内存
    存储设备
    输入设备
    输出设备
    通信设备

一 人机交互方式

  • 常用的dos命令
    dir:列出当前目录下的文件以及文件夹
    md:创建目录
    rd:删除目录 remove directory cd:进入指定目录
    cd…: 退回到上一级目录
    cd\:退回到根目录
    del:删除文件
    exit:推出dos命令行
    help:帮助命令
    cls:dos窗口中清屏可以使用

计算机语言

计算机不理解人类的语言,所以,计算机程序必须使用计算机可以使用的语言编写。现在有数百种编程语言,对于人们来说,开发它们是编程过程更容易。但是,所有的程序都必须转换成计算机可以执行的指令。

  1. 机器语言
    计算机的原生语言因计算机类型的不同而有差异,计算机的原生语言就是机器语言(machine language),即一套内嵌的原子指令集。因为这些指令都是以二进制代码的形式存在,所以,为了以机
    器原生语言的形式给计算机指令,必须以二进制代码输入指令。例如,为进行两个数的相加,可能必须写成如下的二进制形式101101010010010101010101110
  2. 汇编语言
    • 用机器语言进行程序设计是非常单调乏味的过程,而且,所编写的程序也非常难以读懂和修改。为此,在计算机的早期就创建了汇编语言,作为机器语言的替代品。汇编语言(assembly language)使用短的描述性单词(称为助记符)来表示每一条机器语言指令。例如助记符 add 一般表示数字相加,sub 表示数字相减。将数字2和数字3相加得到结果,可以编写如下汇编代码:add 2, 3, result

    • 汇编语言的出现降低了程序设计的难度。然而,由于计算机不理解汇编语言,所以需要使用一种称为汇编器的程序将汇编语言程序转为机器代码。

    • 使用汇编语言编写代码比使用机器语言容易。然而,用汇编语言编写代码依然很不方便。汇编语言中的每一条指令对应机器代码中的一条指令。用汇编语言写代码需要知道CPU是如何工作的。汇编语言被认为是低级语言,因为汇编语言本质上非常接近机器语言,并且是机器相关的。
      在这里插入图片描述

  3. 高级语言
    • 20世纪50年代,新一代编程语言即众所周知的高级语言出现了。它们是平台独立的,这意味着可以
      使用高级语言编程,然后在各种不同类型的机器上运行。高级语言很像英语,易于学习和使用。高级语
      言中的指令称为语句。例如,下面是计算半径为5的圆面积的高级语言语句:area = 5 * 5 * 3.1415926;有许多高级编程语言,每种都为特定目的而设计。
    • 用高级语言编写的程序称为源程序(source program)或源代码(source code)。由于计算机不能运行源程序,源程序必须被翻译成可执行的机器代码。翻译可以由另外一种称为解释器或者编译器的编程工具来完成
    • 解释器:从源代码中读取一条语句,将其翻译为机器代码或者虚拟机器代码,然后立刻运行。
      在这里插入图片描述
    • 编译器:将整个源代码翻译为机器代码文件,然后执行该机器代码文件。
      在这里插入图片描述

二. java 概述

  • 1991 年 Sun 公司的 James Gosling 等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒、PDA 等的微处理器;
    1994 年将 Oak 语言更名为 Java;

1. Java 的三种技术架构:

JAVAEE:Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对 web 程序开发;
JAVASE:Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础;
JAVAME:Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序;

2. Java虚拟机简单讲解

  1. JDK:Java Development Kit,java 的开发和运行环境,java 的开发工具和 jre。
  2. JRE:Java Runtime Environment,java 程序的运行环境,java 运行的所需的类库+JVM(java 虚拟机)。
    论范围讲:JDK>JRE>JVM
  3. 配置环境变量:让 java jdk\bin 目录下的工具,可以在任意目录下运行,原因是,将该工具所在目录告诉了系统,当使用该工具时,由系统帮我们去找指定的目录。
    环境变量的配置: https://blog.csdn.net/o676448/article/details/121896616
  4. javac 命令和 java 命令做什么事情呢?
    要知道 java 是分两部分的:一个是编译,一个是运行。
    javac:负责的是编译的部分,当执行 javac 时,会启动 java 的编译器程序。对指定扩展名的.java 文件进行编译。 生成了 jvm 可以识别的字节码文件。也就是 class 文件,也就是 java 的运行程序。
    java:负责运行的部分.会启动 jvm.加载运行时所需的类库,并对 class 文件进行执行.
    一个文件要被执行,必须要有一个执行的起始点,这个起始点就是 main 函数

三. java 语法基础

1. 关键字:

其实就是某种语言赋予了特殊含义的单词。
保留字:其实就是还没有赋予特殊含义,但是准备日后要使用过的单词。
在这里插入图片描述

2. 标示符:

其实就是在程序中自定义的名词。比如类名,变量名,函数名。包含 0-9、a-z、$、_ ;
注意:数字不可以开头,不可以使用关键字。

3. 常量:

是在程序中的不会变化的数据。

4. 变量:

其实就是内存中的一个存储空间,用于存储常量数据。

  • 作用:方便于运算。因为有些数据不确定。所以确定该数据的名词和存储空间。
  • 特点:变量空间可以重复使用。

5. 注释

注释用于解释说明程序的文字就是注释。有利于提高了代码的阅读性。
注释分类:

  • 单行注释 : // 后到本行结束的所有字符会被编译器忽略;
  • 多行注释 : /* */ 之间的所有字符会被编译器忽略
  • 文档注释 : /** */ 之间的所有字符会被编译器忽略,java特有的(用于生成文档)
    注意:多行和文档注释都不能嵌套使用

6. 常量

在日常生活中,经常使用数据表示事物的某些特性。比如:年龄,身高,日期等等,这些数据都是具体的数值.
那么在Java中像这样的数据如何描述呢?像这样数值确定的数据,Java中用常量来描述。常量其实就是在程序中直接出现的数据,或者叫字面量。

  • 常量:程序中固定不变化的值。比如:整数1,2,3,小数3.14,false,true等。
  • 常量分类
  1. 整数常量:所有整数 三类 正整数 零 负整数
  2. 小数常量:所有小数
  3. 布尔型常量:较为特有,只有两个数值。true false
  4. 字符常量:将一个数字字母或者符号用单引号(‘’)标识
  5. 字符串常量:将一个或者多个字符用双引号(“”)标识
  6. 常量:只有一个数值就是nul

7.进制

  1. 日常生活中,经常使用十进制运算数据,但是也接触过七进制、十二进制等。那么怎么把生活中的这些数据存放在计算机中,计算机又是如何表示这些数据呢?
  2. 任何数据在计算机中都是以二进制的形式存在的。二进制早起由电信号开关演变而来。用开表示某一个数,用关表示某一个数,然后使用不同的开和关组合起来,就可以表示数据了。
  3. 一个整数在内存中一样也是二进制的。
    二进制:每一个二进制数位用0,1 ;满2进1。
    八进制:每一个八进制数位用0,1,2,3,4,5,6,7 ;满8进1。用0开头表示。
    十进制:每一个十进制数位用0,1,2,3,4,5,6,7 ,8,9 ;满10进1。 满10进1。
    十六进制:每一个十六进制数位用0,1,2,3,4,5,6,7 ,8,9,A,B,C,D,E,F ;满16进1。 满16进1.。用0x开头表示
  • 进制转换
  1. 既然知道计算机中存储的都是二进制数据,那么如何将生活中的十进制数据转换成计算机能够识别的二进制数数据呢
    十进制转二进制:十进制转成二进制—>除以2倒取余数
    在这里插入图片描述
  2. 二进制数转十进制数:二进制转成十进制—>按2的幂数展开并累加

在这里插入图片描述

  • 进制规律
  1. 计算机中是以二进制数据的形式表示所有数据,并且在计算机中把8个二进制数位当做一组,并“字 节”来表示。即:8bit = 1Byte (八个二进制数位为一个字节)。那么一个字节能表示的数据是多大呢?
    也就是当八个二进制数位上全部是1时能表达多大一个数据呢
    在这里插入图片描述
    即当1个字节上全部存放的是1时,这个数据即就是255,0-255之间的任何一个正数都可以在用一个字节表示。
  • 其他进制转换
  1. 发现将一个十进制数转成二进制数时,需要使用很长的01这样的数字表示,很麻烦,不利于书写和
    阅读,于是就想能不能把这个较长的01数字使用其他形式表示呢?
  2. 如果把一个二进制数按照每三个二进制数位为一组划分,发现这三个二进制数位数字能表示大的最
    大值正好为7,正好符号了八进制的表示形式。于是可以把二进制数用八进制的形式表示
    在这里插入图片描述
  • 负数的表示形式
  1. 对于一个负数,它的表示形式非常简单,即用这个负数所对应的正数的二进制数取反然后加1,即
    可得到这个负数的二进制表现形式。取反的意思是将当前二进制数位上的1变0,0变1
    在这里插入图片描述

8. 数据类型

  1. 基本数据类型:byte、short、int、long、float、double、char、boolean
  2. 引用数据类型: 数组、类、接口。
    级别从低到高为:byte,char,short(这三个平级)–>int–>float–>long–>double
    自动类型转换:从低级别到高级别,系统自动转的;
    强制类型转换:什么情况下使用?把一个高级别的数赋给一个别该数的级别低的变量;
    在这里插入图片描述
    整数常量默认:int 小数常量默认:double

9. 运算符号:

  • 算术运算符。
    . + - * / % %:任何整数模 2 不是 0 就是 1,所以只要改变被模数就可以实现开关运算。
    在这里插入图片描述
    +:连接符。
    ++,–

  • 赋值运算符。
    = += -= *= /= %=
    在这里插入图片描述

  • 比较运算符。
    特点:该运算符的特点是:运算完的结果,要么是 true,要么是 false。
    在这里插入图片描述

  • 逻辑运算符。
    & | ^ ! && ||
    逻辑运算符除了 ! 外都是用于连接两个 boolean 类型表达式。
    &: 只有两边都为 true 结果是 true。否则就是 false。
    |:只要两边都为 false 结果是 false,否则就是 true
    ^:异或:和或有点不一样。
    两边结果一样,就为 false。
    两边结果不一样,就为 true
    在这里插入图片描述

  • & 和 &&区别
    & :无论左边结果是什么,右边都参与运算。
    &&:短路与,如果左边为 false,那么右边不参数与运算。
    | 和|| 区别:|:两边都运算。
    ||:短路或,如果左边为 true,那么右边不参与运算。
    位运算符:用于操作二进制位的运算符。
    & | ^
    << >> >>>(无符号右移)

  • 练习:高效的算出 2*8 = 2<<3;

10. 语句

** If switch do while while for **

  • 当判断固定个数的值的时候,可以使用 if,也可以使用 switch。
    但是建议使用 switch,效率相对较高。
    1. switch(变量){
      case 值:要执行的语句;break;

      default:要执行的语句; }
      工作原理:用小括号中的变量的值依次和 case 后面的值进行对比,和哪个 case 后面的值相同了就执行哪个 case 后面的语句,如果没有相同的则执行 default 后面的语句;
    2. 细节
      • break 是可以省略的,如果省略了就一直执行到遇到 break 为止;
      • switch 后面的小括号中的变量应该是 byte,char,short,int 四种类型中的一种;
      • default 可以写在 switch 结构中的任意位置;如果将 default 语句放在了第一行,则不管
        expression 与 case 中的 value 是否匹配,程序会从 default 开始执行直到第一个 break 出现。
      • 当判断数据范围,获取判断运算结果 boolean 类型时,需要使用 if。
      • 当某些语句需要执行很多次时,就用循环结构。
      • while 和 for 可以进行互换。
        区别在于:如果需要定义变量控制循环次数。建议使用 for。因为 for 循环完毕,变量在内存中释放。
        break:作用于 switch ,和循环语句,用于跳出,或者称为结束。
        break 语句单独存在时,下面不要定义其他语句,因为执行不到,编译会失败。当循环嵌套时,break 只跳出当
        前所在循环。要跳出嵌套中的外部循环,只要给循环起名字即可,这个名字称之为标号。
        continue:只作用于循环结构,继续循环用的。
        作用:结束本次循环,继续下次循环。该语句单独存在时,下面不可以定义语句,执行不到。

11. 函 数:

  1. 为了高代码的复用性,可以将其定义成一个单独的功能,该功能的体现就是 java 中的函数。函数
    就是体现之一。

  2. java 中的函数的定义格式

修饰符 返回值类型 函数名(参数类型 形式参数 1,参数类型 形式参数 1,…){ 
             执行语句; return 返回值;
 } 
  • 当函数没有具体的返回值时,返回的返回值类型用 void 关键字表示。
  • 如果函数的返回值类型是 void 时,return 语句可以省略不写的,系统会帮你自动加上。
  • return 的作用:结束函数。结束功能。
  1. 如何定义一个函数
    1. 函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:
  • 明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。

  • 在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&
    参数个数)。

  • 函数的作用:

    1. 用于定义功能。
    2. 用于封装代码ᨀ高代码的复用性。
    3. 注意:函数中只能调用函数,不能定义函数。
  • 主函数:

    1. 保证该类的独立运行。
    2. 因为它是程序的入口。
    3. 因为它在被 jvm 调用。
  • 函数定义名称是为什么呢?

    1. 为了对该功能进行标示,方便于调用。
    2. 为了通过名称就可以明确函数的功能,为了增加代码的阅读性
  • 重载的定义是:在一个类中,如果出现了两个或者两个以上的同名函数,只要它们的参数的个数,或者参数的
    记住一句话:同名不同参,返回值无关

12. 函数的递归

  1. 递归的体现就是函数自身调用函数自身。
    一般而言,但凡能够被迭代(循环)解决的问题,递归都可以;递归解决的问题,迭代就不一定
    了。
    递归其实是分治法的一种实现方式(一种实现思路)。
    递归就是函数在进栈,进栈的次数多了,势必会占内存,无法避免的
  • 在某些问题上,递归所写的代码要比迭代写的代码少
  • 在某些问题上,迭代是写不出来的,所以只能用递归
  1. 分治法是一种算法思想,分治法主要解决的问题是将大问题,进行拆分,拆分成若干个小的问题进
    行求解,最终将每个小问题的解进行合并。其实,分治法就是一种暴力破解法(穷举),也是一种搜索
    最优答案的算法。
    先递后归
  • 前进段:指的就是将问题从大化小
  • 结束段:问题无法再继续化小,则处理当前的问题
  • 返回段:将小问题处理完张之后,向上返回(有些问题是不需要返回的)

四. 常用类

1. Math类

Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

  • 自带常量
    static double E :比任何其他值都更接近 e (即自然对数的底数)的 double 值。
    static double PI : 比任何其他值都更接近 pi (即圆的周长与直径之比)的 double 值。
  • 取整方法
    static double ceil(double a) :返回最小的(最接近负无穷大) double 值,该值大于等于参
    数,并等于某个整数。
    static double floor(double a) :返回最大的(最接近正无穷大) double 值,该值小于等于参
    数,并等于某个整数。
    static double rint(double a) :返回最接近参数并等于某一整数的 double 值。
    static long round(double a) :返回最接近参数的 long 。
  • 三角函数方法
    static double sin(double a) :返回角的三角正弦。 static double cos(double a) :返回角的三角余弦。
    static double tan(double a) :返回角的三角正切。
    static double toDegrees(double angrad) :将用弧度表示的角转换为近似相等的用角度表示的
    角。
    static double toRadians(double angdeg) :将用角度表示的角转换为近似相等的用弧度表示的
    角。
    static double asin(double a) :返回一个值的反正弦;返回的角度范围在 - pi /2 到 pi /2 之间。
    static double acos(double a) :返回一个值的反余弦;返回的角度范围在 0.0 到 pi 之间。
    static double atan(double a) :返回一个值的反正切;返回的角度范围在 - pi /2 到 pi /2 之间。
  • 指数函数方法
    outer:for (int x=0; x<3 ;x++ ) { inner:for (int y=0; y<4 ;y++ ) { System.out.println(“x=”+x); break outer; } }outer:for (int x=0; x<3 ;x++ ) { inner:for (int y=0; y<4 ;y++ ) { System.out.println(“x=”+x); continue outer; } }
    static double exp(double a) :返回欧拉数 e 的 double 次幂的值。
    static double log(double a) :返回 double 值的自然对数(底数是 e )。
    static double log10(double a) :返回 double 值的底数为 10 的对数。
    static double pow(double a, double b) :返回第一个参数的第二个参数次幂的值。
    static double sqrt(double a) :返回正确舍入的 double 值的正平方根。
    static double cbrt(double a) :返回 double 值的立方根。
  • 其他方法
    static double abs(double a) :返回 double 值的绝对值。
    static double hypot(double x, double y) :返回 sqrt( x 2 + y 2),没有中间溢出或下溢。
    static double max(double a, double b) :返回两个 double 值中较大的一个。
    static double min(double a, double b) :返回两个 double 值中较小的一个。
    static double random() :返回带正号的 double 值,该值大于等于 0.0 且小于 1.0 。

2. Scanner类

  • 一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
  • Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配。然后可以
    使用不同的 next 方法将得到的标记转换为不同类型的值。
  1. String next() :查找并返回来自此扫描器的下一个完整标记。
  2. boolean nextBoolean() :扫描解释为一个布尔值的输入标记并返回该值。
  3. byte nextByte() :将输入信息的下一个标记扫描为一个 byte 。 double nextDouble() :将输入信息的下一个标记扫描为一个 double 。 float nextFloat() :将输入信息的下一个标记扫描为一个 float 。 intnextInt() :将输入信息的下一个标记扫描为一个 int 。 String nextLine() :此扫描器执行当前行,并返回跳过的输入信息。
  4. long nextLong() :将输入信息的下一个标记扫描为一个 long 。 short nextShort() :将输入信息的下一个标记扫描为一个 short 。

3. Random类

  • 此类的实例用于生成伪随机数流。
  1. boolean nextBoolean() :返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的boolean 值。
  2. double nextDouble() :返回下一个伪随机数,它是取自此随机数生成器序列的在 0.0 和 1.0 之间均匀分布的 double 值。
  3. int nextInt() :返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。
  4. int nextInt(int n) :返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定
    值(不包括)之间均匀分布的 int 值。

4. String类

  • String 类代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实
    现。 字符串是常量;它们的值在创建之后不能更改,因为 String 对象是不可变的,所以可以共享。
  1. 获取相关
    char charAt(int index) :返回指定索引处的 char 值。
    int indexOf(int ch) :返回指定字符在此字符串中第一次出现处的索引。
    int indexOf(int ch, int fromIndex) :返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
    int indexOf(String str) :返回指定子字符串在此字符串中第一次出现处的索引。
    int indexOf(String str, int fromIndex) :返回指定子字符串在此字符串中第一次出现处的索引,
    从指定的索引开始。
    int lastIndexOf(int ch) :返回指定字符在此字符串中最后一次出现处的索引。
    int length() :返回此字符串的长度。
    String[] split(String regex) : 根据给定正则表达式的匹配拆分此字符串。
    String substring(int beginIndex) :返回一个新的字符串,它是此字符串的一个子字符串。
    String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串的一个子字
    符串。
  2. 判断相关
    int compareTo(String anotherString) :按字典顺序比较两个字符串。
    int compareToIgnoreCase(String str) :按字典顺序比较两个字符串,不考虑大小写。
    boolean contains(CharSequence s) :当且仅当此字符串包含指定的 char 值序列时,返回
    true。 boolean endsWith(String suw ix) :测试此字符串是否以指定的后缀结束。
    boolean equals(Object anObject) :将此字符串与指定的对象比较。
    boolean equalsIgnoreCase(String anotherString) :将此 String 与另一个 String 比较,不
    考虑大小写。
    boolean isEmpty() :当且仅当 length() 为 0 时返回 true 。 boolean startsWith(String prefix) :测试此字符串是否以指定的前缀开始。
    boolean startsWith(String prefix, int tow set) :测试此字符串从指定索引开始的子字符串是否以
    指定前缀开始。
  3. 修改相关
    String replace(char oldChar, char newChar) :返回一个新的字符串,它是通过用 newChar 替
    换此字符串中出现的所有 oldChar 得到的。
    String replace(CharSequence target, CharSequence replacement) :使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
    String toLowerCase() :使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
    String toUpperCase() :使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
    String trim() :返回字符串的副本,忽略前导空白和尾部空白。
  4. 字符串格式化输出
    在这里插入图片描述

五 数组

一维数组

1. 概述

用于存储同一类型数据的一个容器。好处:可以对该容器中的数据进行编号,从 0 开始。数组用于
封装数据,就是一个具体的实体。

2. 格式

  • 元素类型[] 变量名 = new 元素类型[元素的个数];
  • 元素类型[] 变量名 = {元素 1,元素 2…};
    元素类型[] 变量名 = new 元素类型[]{元素 1,元素 2…};

3. 注意要点

  1. 数组就是一片地址连续且空间大小一致的存储空间(但是每个空间存的还是其他数据的地址
  2. 数组存在于堆内存中,但凡在堆中存储的数据都称之为对象
  3. 数组提供角标来访问数组当中的元素
  4. 数组变量存的就是数组在堆内存中首元素的地址
  5. 数组通过角标来访问元素的具体计算方式是:所要访问数据的地址 = 首元素地址 + 角标 * 数
    据类型大小
  6. 数组一旦定义下来,其长度不可改变;数组中有几个地址?就看数组有几个元素空间(数组
    的长度)
  7. 创建数组时必须明确规定大小或内容

4. 数组遍历

public class ArrayTraversal {
    public static void main(String[] args) {
          int[] arr = new int[] { 1, 2, 3, 4, 5, 6 };
              for (int i = 0; i < arr.length; i++) { 
              System.out.println(arr[i]);
               }
              for (int i : arr) {
               System.out.println(i); 
              }
  } 
}

5. 数组最值

public class ArrayMaxMinValue {
      public static void main(String[] args) { 
               int[] arr = new int[] { 1, 2, 3, 4, 5, 6 }; 
               int max = arr[0]; 
               int min = arr[1];
             for (int i = 0; i < arr.length; i++) { 
                  if (arr[i] < min) { 
                     min = arr[i]; 
                 }if (arr[i] > max) {
                  max = arr[i]; 
                   } 
}
      System.out.println("min = " + min); System.out.println("max = " + max);
              } 
 }

二维数组

1. 概述

  • 就是一个由行和列组成的一个表格而已,矩阵Matrix。
  • 在这个矩阵中访问元素的话,是根据元素的行角标和列角标所确定的。
  • 二维数组具体是在内存中如何存储的呢?
    无论是二维数组,还是多维数组,它们本身就是一个一维数组。
    尤其对于二维数组而言,无非就是一个一维数组,只不过该一维数组中的每一个元素是另一个
    一维数组罢了。

2. 定义方式

在这里插入图片描述

六. 面向对象的编程入门

1. 特点:

1:将复杂的事情简单化。

2:面向对象将以前的过程中的执行者,变成了指挥者。

3:面向对象这种思想是符合现在人们思考习惯的一种思想。

  • 过程和对象在我们的程序中是如何体现的呢?过程其实就是函数;对象是将函数等一些内容进行了封装。

4:匿名对象使用场景:

  • 当对方法只进行一次调用的时候,可以使用匿名对象。

5:当对象对成员进行多次调用时,不能使用匿名对象。必须给对象起名字。
在类中定义其实都称之为成员。成员有两种:

  • 成员变量:其实对应的就是事物的属性。
  • 成员函数:其实对应的就是事物的行为。
  • 所以,其实定义类,就是在定义成员变量和成员函数。但是在定义前,必须先要对事物进行属性和行为的分析,才可以用代码来体现。

6:private int age;//私有的访问权限最低,只有在本类中的访问有效。

  • 注意:私有仅仅是封装的一种体现形式而已。
  • 私有的成员:其他类不能直接创建对象访问,所以只有通过本类对外ᨀ供具体的访问方式来完成对私有的访问,可以通过对外提供函数的形式对其进行访问。
  • 好处:可以在函数中加入逻辑判断等操作,对数据进行判断等操作。
  • 总结:开发时,记住,属性是用于存储数据的,直接被访问,容易出现安全隐患,所以,类中的属性通常被私有化,并对外提供公共的访问方法。
    这个方法一般有两个,规范写法:对于属性 xxx,可以使用 setXXX(),getXXX()对其进行操作。

2. 类中怎么没有定义主函数呢?

注意:主函数的存在,仅为该类是否需要独立运行,如果不需要,主函数是不用定义的。
主函数的解释 :保证所在类的独立运行,是程序的入口,被 jvm 调用。

  • 成员变量和局部变量的区别:
    1:成员变量直接定义在类中。
    局部变量定义在方法中,参数上,语句中。
    2:成员变量在这个类中有效。
    局部变量只在自己所属的大括号内有效,大括号结束,局部变量失去作用域。 3:成员变量存在于堆内存中,随着对象的产生而存在,消失而消失。
    局部变量存在于栈内存中,随着所属区域的运行而存在,结束而释放。
    构造函数:用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种。
  • 特点
    1:该函数的名称和所在类的名称相同。
    2:不需要定义返回值类型。
    3:该函数没有具体的返回值。
    记住:所有对象创建时,都需要初始化才可以使用。
    注意事项:一个类在定义时,如果没有定义过构造函数,那么该类中会自动生成一个空参数的构造函数,为了方便该类创建对象,完成初始化。如果在类中自定义了构造函数,那么默认的构造函数就没有了。
    一个类中,可以有多个构造函数,因为它们的函数名称都相同,所以只能通过参数列表来区分。所以,一个类中如果出现多个构造函数。它们的存在是以重载体现的。
  • 构造函数和一般函数有什么区别呢?
    1:两个函数定义格式不同。
    2:构造函数是在对象创建时,就被调用,用于初始化,而且初始化动作只执行一次。
    一般函数,是对象创建后,需要调用才执行,可以被调用多次。
  • 什么时候使用构造函数呢?
  1. 分析事物时,发现具体事物一出现,就具备了一些特征,那就将这些特征定义到构造函数内。
  2. 构造代码块和构造函数有什么区别? 构造代码块:是给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块。只要对象一建立。
    就会调用这个代码块。
  • 构造函数:是给与之对应的对象进行初始化。它具有针对性。
    Person p = new Person();
  • 创建一个对象都在内存中做了什么事情?
    1:先将硬盘上指定位置的 Person.class 文件加载进内存。
    2:执行 main 方法时,在栈内存中开辟了 main 方法的空间(压栈-进栈),然后在 main 方法的栈区分配了一个变量 p。
    3:在堆内存中开辟一个实体空间,分配了一个内存首地址值。new
    4:在该实体空间中进行属性的空间分配,并进行了默认初始化。
    5:对空间中的属性进行显示初始化。
    6:进行实体的构造代码块初始化。
    7:调用该实体对应的构造函数,进行构造函数初始化。
    8:将首地址赋值给 p ,p 变量就引用了该实体。(指向了该对象)

3. 封 装(面向对象特征之一):是指隐藏对象的属性和实现细节,仅对外供公共访问方式。

  • 好处:将变化隔离;便于使用;ᨀ高重用性;安全性。
  • 封装原则:将不需要对外ᨀ供的内容都隐藏起来,把属性都隐藏,ᨀ供公共方法对其访问。
  • this:代表对象。就是所在函数所属对象的引用。
  • this 到底代表什么呢?哪个对象调用了 this 所在的函数,this 就代表哪个对象,就是哪个对象的引用。
  • 开发时,什么时候使用 this 呢?
  1. 在定义功能时,如果该功能内部使用到了调用该功能的对象,这时就用 this 来表示这个对象。
    this 还可以用于构造函数间的调用。
  2. 调用格式:this(实际参数);
  3. this 对象后面跟上 . 调用的是成员属性和成员方法(一般方法);
  4. this 对象后面跟上 () 调用的是本类中的对应参数的构造函数。
  5. 注意:用 this 调用构造函数,必须定义在构造函数的第一行。因为构造函数是用于初始化的,所以初
    始化动作一定要执行。否则编译失败。
  6. static:关键字,是一个修饰符,用于修饰成员(成员变量和成员函数)。
  • 特点
  1. 想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。
  2. 被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态
    方式。
  3. 静态随着类的加载而加载。而且优先于对象存在。
  • 弊端:
    1. 有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。
      这样对事物的᧿述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。
    2. 静态方法只能访问静态成员,不可以访问非静态成员。
      因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。
    3. 静态方法中不能使用 this,super 关键字。
      因为 this 代表对象,而静态在时,有可能没有对象,所以 this 无法使用。
    4. 主函数是静态的。
  • 什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢?
    成员分两种:
    1. 成员变量。(数据共享时静态化)
      该成员变量的数据是否是所有对象都一样:
      如果是,那么该变量需要被静态修饰,因为是共享的数据。
      如果不是,那么就说这是对象的特有数据,要存储到对象中。
    2. 成员函数。(方法中没有调用特有数据时就定义成静态)
      如果判断成员函数是否需要被静态修饰呢?
      只要参考,该函数内是否访问了对象中的特有数据:
      如果有访问特有数据,那方法不能被静态修饰。
      如果没有访问过特有数据,那么这个方法需要被静态修饰。
  • 成员变量和静态变量的区别:
    1. 成员变量所属于对象。所以也称为实例变量。
      静态变量所属于类。所以也称为类变量。
    2. 成员变量存在于堆内存中。
      静态变量存在于方法区中。
    3. 成员变量随着对象创建而存在。随着对象被回收而消失。
      静态变量随着类的加载而存在。随着类的消失而消失。
    4. 成员变量只能被对象所调用 。
      静态变量可以被对象调用,也可以被类名调用。
      所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。
  1. 静态的注意:静态的生命周期很长。
    静态代码块:就是一个有静态关键字标示的一个代码块区域。定义在类中。
    作用:可以完成类的初始化。静态代码块随着类的加载而执行,而且只执行一次(new 多个对象就只执
    行一次)。如果和主函数在同一类中,优先于主函数执行。 Public:访问权限最大。
    static:不需要对象,直接类名即可。
    void:主函数没有返回值。
    Main:主函数特定的名称。
    (String[] args):主函数的参数,是一个字符串数组类型的参数,jvm 调用 main 方法时,传递的实际参数是
    new String[0]。
  • jvm 默认传递的是长度为 0 的字符串数组,我们在运行该类时,也可以指定具体的参数进行传递。可以在控制台,运行该类时,在后面加入参数。参数之间通过空格隔开。jvm 会自动将这些字符串参数作为 args 数组中的元素,进行存储。
  • 静态代码块、构造代码块、构造函数同时存在时的执行顺序:静态代码块 构造代码块 构造函数;
    生成 Java 帮助文档:命令格式:javadoc –d 文件夹名 –auther –version *.java
/ ** 



*/

4. 设计模式

  • 设计模式
    解决问题最行之有效的思想。是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
  • java 中有 23 种设计模式:
    单例设计模式: ★★★★★
    解决的问题:保证一个类在内存中的对象唯一性。
    比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。Runtime()方法就是单例设计模式进行设计的。
    如何保证对象唯一性呢?
    1. 思想:
      不让其他程序创建该类对象。
      在本类中创建一个本类对象。
      对外提供方法,让其他程序获取这个对象。
    2. 步骤: 1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该类对象; 2,就在类中创建一个本类的对象; 3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
    3. 代码体现: 1,私有化构造函数; 2,创建私有并静态的本类对象; 3,定义公有并静态的方法,返回该对象。
//饿汉式
class Single{
private Single(){} //私有化构造函数。 
private static Single s = new Single(); //创建私有并静态的本类对象。
public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
return s;
} }
//懒汉式:延迟加载方式。
class Single2{
private Single2(){}
private static Single2 s = null;
public static Single2 getInstance(){
if(s==null)
s = new Single2();
return s;
} }

5. 继 承(面向对象特征之一)

  • 好处
    1:提高了代码的复用性。
    2:让类与类之间产生了关系,提供了另一个特征多态的前提。

  • 父类的由来
    其实是由多个类不断向上抽取共性内容而来的。
    java 中对于继承,java 只支持单继承。java 虽然不直接支持多继承,但是保留了这种多继承机制,进行改良。
    单继承:一个类只能有一个父类。
    多继承:一个类可以有多个父类。

  • 为什么不支持多继承呢

    1. 因为当一个类同时继承两个父类时,两个父类中有相同的功能,那么子类对象调用该功能时,运行哪一个呢?
      因为父类中的方法中存在方法体。
      但是 java 支持多重继承。A 继承 B B 继承 C C 继承 D。
    2. 多重继承的出现,就有了继承体系。体系中的顶层父类是通过不断向上抽取而来的。它里面定义的该体系最基本最共性内容的功能。
      所以,一个体系要想被使用,直接查阅该系统中的父类的功能即可知道该体系的基本用法。那么想要使用一个体系时,需要建立对象。建议建立最子类对象,因为最子类不仅可以使用父类中的功能。还可以使用子类特有的一些功能。
    3. 简单说:对于一个继承体系的使用,查阅顶层父类中的内容,创建最底层子类的对象。
  • 子父类出现后,类中的成员都有了哪些特点
    1:成员变量。

    1. 当子父类中出现一样的属性时,子类类型的对象,调用该属性,值是子类的属性值。
      如果想要调用父类中的属性值,需要使用一个关键字:super This:代表是本类类型的对象引用。 Super:代表是子类所属的父类中的内存空间引用。
      注意:子父类中通常是不会出现同名成员变量的,因为父类中只要定义了,子类就不用在定义了,直接继
      承过来用就可以了。

    2. 成员函数。
      当子父类中出现了一模一样的方法时,建立子类对象会运行子类中的方法。好像父类中的方法被覆盖掉一样。
      所以这种情况,是函数的另一个特性:覆盖(复写,重写)
      什么时候使用覆盖呢?当一个类的功能内容需要修改时,可以通过覆盖来实现。

    3. 构造函数。
      发现子类构造函数运行时,先运行了父类的构造函数。为什么呢?
      原因:子类的所有构造函数中的第一行,其实都有一条隐身的语句 super();
      super(): 表示父类的构造函数,并会调用于参数相对应的父类中的构造函数。而 super():是在调用父类
      中空参数的构造函数。
      为什么子类对象初始化时,都需要调用父类中的函数?(为什么要在子类构造函数的第一行加入这个
      super()?)
      因为子类继承父类,会继承到父类中的数据,所以必须要看父类是如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。

    4. 注意:子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造内第
      一行都有默认的语句 super();
      如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过 super 语句指定要访问的父
      类中的构造函数。
      如果子类构造函数中用 this 来指定调用子类自己的构造函数,那么被调用的构造函数也一样会访
      问父类中的构造函数。

    5. 问题:super()和 this()是否可以同时出现的构造函数中。
      两个语句只能有一个定义在第一行,所以只能出现其中一个。
      super()或者 this():为什么一定要定义在第一行?
      因为 super()或者 this()都是调用构造函数,构造函数用于初始化,所以初始化的动作要先完成。

  • 继承的细节:

    1. 什么时候使用继承呢?
      当类与类之间存在着所属关系时,才具备了继承的前ᨀ。a 是 b 中的一种。a 继承 b。狼是犬科中的一种。
      英文书中,所属关系:" is a "
    2. 注意:不要仅仅为了获取其他类中的已有成员进行继承。
      所以判断所属关系,可以简单看,如果继承后,被继承的类中的功能,都可以被该子类所具备,那么继承成立。如果不是,不可以继承。
    • 细节二:
      在方法覆盖时,注意两点:
    1. 子类覆盖父类时,必须要保证,子类方法的权限必须大于等于父类方法权限可以实现继承。否则,编译
      失败。
    2. 覆盖时,要么都静态,要么都不静态。 (静态只能覆盖静态,或者被静态覆盖)
      继承的一个弊端:打破了封装性。对于一些类,或者类中功能,是需要被继承,或者复写的。
      这时如何解决问题呢?介绍一个关键字,final:最终。
    3. final 特点: 1:这个关键字是一个修饰符,可以修饰类,方法,变量。 2:被 final 修饰的类是一个最终类,不可以被继承。 3:被 final 修饰的方法是一个最终方法,不可以被覆盖。 4:被 final 修饰的变量是一个常量,只能赋值一次。
    4. 其实这样的原因的就是给一些固定的数据起个阅读性较强的名称。
      不加 final 修饰不是也可以使用吗?那么这个值是一个变量,是可以更改的。加了 final,程序更为严谨。
      常量名称定义时,有规范,所有字母都大写,如果由多个单词组成,中间用 _ 连接。

6. 抽象类

  • 抽象:不具体,看不明白。抽象类表象体现
    在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字 abstract 所标示,声明为抽象方法。
    抽象方法所在类一定要标示为抽象类,也就是说该类需要被 abstract 关键字所修饰。

  • 抽象类的特点

    1. 抽象方法只能定义在抽象类中,抽象类和抽象方法必须由 abstract 关键字修饰(可以᧿述类和
      方法,不可以提述变量)。
    2. 抽象方法只定义方法声明,并不定义方法实现。 3:抽象类不可以被创建对象(实例化)。 4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,
      该子类还是一个抽象类。
  • 抽象类的细节

    1. 抽象类中是否有构造函数?有,用于给子类对象进行初始化。
    2. 抽象类中是否可以定义非抽象方法? 可以。其实,抽象类和一般类没有太大的区别,都是在᧿述事物,只不过抽象类在᧿述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。
    3. 抽象关键字 abstract 和哪些不可以共存?final , private , static
    4. 抽象类中可不可以不定义抽象方法?可以。抽象方法目的仅仅为了不让该类创建对象。
  • 模板方法设计模式
    解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

abstract class GetTime{
public final void getTime(){ //此功能如果不需要复写,可加 final 限定
long start = System.currentTimeMillis();
code(); //不确定的功能部分,ᨀ取出来,通过抽象方法实现 
long end = System.currentTimeMillis();
System.out.println("毫秒是:"+(end-start));
               }
public abstract void code(); //抽象不确定的功能,让子类复写实现 }
class SubDemo extends GetTime{
public void code(){ //子类复写功能方法
for(int y=0; y<1000; y++){
System.out.println("y");
       }
   }
 }

7 接 口★★★★★

  • 都是用关键字 interface 定义的。
  • 接口中包含的成员,最常见的有全局常量、抽象方法。
    1. 注意:接口中的成员都有固定的修饰符。
    2. 成员变量:public static final 成员方法:public abstract
interface Inter{
public static final int x = 3;
public abstract void show();
} 
  1. 接口中有抽象方法,说明接口不可以实例化。接口的子类必须实现了接口中所有的抽象方法后,该子
    类才可以实例化。否则,该子类还是一个抽象类。
  2. 类与类之间存在着继承关系,类与接口中间存在的是实现关系。
    继承用 extends ;实现用 implements ; 5:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。java 将多继承机制通过
    多现实来体现。
  3. 一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。
  4. 其实 java 中是有多继承的。接口与接口之间存在着继承关系,接口可以多继承接口。
  • 接口都用于设计上,设计上的特点:(可以理解主板上提供的接口)

    1. 接口是对外提供的规则。
    2. 接口是功能的扩展。
    3. 接口的出现降低了耦合性。
      抽象类与接口:
      抽象类:一般用于提述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。
      接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。
      抽象类和接口的共性:都是不断向上抽取的结果。
  • 抽象类和接口的区别

    1. 抽象类只能被继承,而且只能单继承。
      接口需要被实现,而且可以多实现。
    2. 抽象类中可以定义非抽象方法,子类可以直接继承使用。
      接口中都有抽象方法,需要子类去实现。
    3. 抽象类使用的是 is a 关系。
      接口使用的 like a 关系。
    4. 抽象类的成员修饰符可以自定义。
      接口中的成员修饰符是固定的。全都是 public 的。
      在开发之前,先定义规则,A 和 B 分别开发,A 负责实现这个规则,B 负责使用这个规则。至于 A 是如何对规则具体实现的,B 是不需要知道的。这样这个接口的出现就降低了 A 和 B 直接耦合性。

8 多态★★★★★(面向对象特征之一)

函数本身就具备多态性,某一种事物有不同的具体的体现

  • 体现
    父类引用或者接口的引用指向了自己的子类对象。//Animal a = new Cat();
  • 多态的好处:提高了程序的扩展性。
  • 多态的弊端:当父类引用指向子类对象时,虽然ᨀ高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)
  • 多态的前提
    1. 必须要有关系,比如继承、或者实现。
    2. 通常会有覆盖操作。
  • 多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。
class 毕姥爷{
void 讲课(){
System.out.println("企业管理");
}
void 钓鱼(){
System.out.println("钓鱼");
} }
class 毕老师 extends 毕姥爷{
void 讲课(){
System.out.println("JAVA");
}
void 看电影(){
System.out.println("看电影");
} }
class {
public static void main(String[] args) {
毕姥爷 x = new 毕老师(); //毕老师对象被ᨀ升为了毕姥爷类型。
// x.讲课();
// x.看电影(); //错误.
毕老师 y = (毕老师)x; //将毕姥爷类型强制转换成毕老师类型。
y.看电影();//在多态中,自始自终都是子类对象在做着类型的变化。
} } 
  • 如果想用子类对象的特有方法,如何判断对象是哪个具体的子类类型呢
    可以可以通过一个关键字 instanceof ;//判断对象是否实现了指定的接口或继承了指定的类

  • 格式:<对象 instanceof 类型> ,判断一个对象是否所属于指定的类型。
    Student instanceof Person = true;//student 继承了 person 类

  • 多态在子父类中的成员上的体现的特点

  1. 成员变量:
    在多态中,子父类成员变量同名。
    在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错
    误)
    运行时期:也是参考引用型变量所属的类中是否有调用的成员。
    简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。
    再说的更容易记忆一些:成员变量 — 编译运行都看 = 左边。
  2. 成员函数。
    编译时期:参考引用型变量所属的类中是否有调用的方法。
    运行事情:参考的是对象所属的类中是否有调用的方法。
    为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。
    简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。
    更简单:成员函数 — 编译看 = 左边,运行看 = 右边。
  3. 静态函数。
    编译时期:参考的是引用型变量所属的类中是否有调用的成员。
    运行时期:也是参考引用型变量所属的类中是否有调用的成员。
    为什么是这样的呢?因为静态方法,其实不所属于对象,而是所属于该方法所在的类。
    调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。
    简单说:静态函数 — 编译运行都看 = 左边。

9. Object类

所有类的直接或者间接父类,Java 认为所有的对象都具备一些基本的共性内容,这些内容可以不
断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能。

  • boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。
    而根据对象的属性不同,判断对象是否相同的具体内容也不一样。所以在定义类时,一般都会复写 equals 方法,建立本类特有的判断对象是否相同的依据
    具体方法:
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.age == p.age;
}
  • String toString():将对象变成字符串;默认返回的格式:类名@哈希值 = getClass().getName() +
    ‘@’ + Integer.toHexString(hashCode())为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式
    具体方法:
public String toString(){
return "person : "+age;
}
  • Class getClass():获取任意对象运行时的所属字节码文件对象
  • int hashCode():返回该对象的哈希码值。支持此方法是为了ᨀ高哈希表的性能
    通常 equals,toString,hashCode,在应用中都会被复写,建立具体对象的特有的内容。

10. 内部类

如果 A 类需要直接访问 B 类中的成员,而 B 类又需要建立 A 类的对象。这时,为了方便设计和访问,直接将 A 类定义在 B 类中。就可以了。A 类就称为内部类。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象

class Outer{
int num = 4;
class Inner {
void show(){
System.out.println("inner show run "+num);
} }
public void method(){
Inner in = new Inner();//创建内部类的对象。
in.show();//调用内部类的方法。
} }
  • 当内部类定义在外部类中的成员位置上,可以使用一些成员修饰符修饰 private、static。
  1. 默认修饰符。
    直接访问内部类格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
    Outer.Inner in = new Outer.new Inner();//这种形式很少用。
    但是这种应用不多见,因为内部类之所以定义在内部就是为了封装。想要获取内部类对象通常都通过外
    部类的方法来获取。这样可以对内部类对象进行控制。
  2. 私有修饰符。
    通常内部类被封装,都会被私有化,因为封装性不让其他程序直接访问。
  3. 静态修饰符。
    如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。
    注意;如果内部类中定义了静态成员,那么该内部类必须是静态的。
  • 内部类编译后的文件名为:外部类名$内部类名.java

  • 为什么内部类可以直接访问外部类中的成员呢?
    那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this
    内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。
    当内部类被定义在局部位置上,只能访问局部中被 final 修饰的局部变量。

  • **匿名内部类:**没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式。匿名内部类其实就是一个匿名子类对象。

    • 想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口。
    • 匿名内部类的格式:new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法
  • 匿名内部类的使用场景:
    当函数的参数是接口类型引用时,如果接口中的方法不超过 3 个。可以通过匿名内部类来完成参数的传递。
    其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。

  • 面试1

//1 
new Object(){
void show(){
System.out.println("show run");
} }.show();
//2 
Object obj = new Object(){
void show(){
System.out.println("show run");
}
};
obj.show();

1 和 2 的写法正确吗?有区别吗?说出原因。
写法是正确,1 和 2 都是在通过匿名内部类建立一个 Object 类的子类对象。
区别:
第一个可是编译通过,并运行。
第二个编译失败,因为匿名内部类是一个子类对象,当用 Object 的 obj 引用指向时,就被ᨀ升为了
Object 类型,而编译时检查 Object 类中是否有 show 方法,所以编译失败

  • 面试2
class InnerClassDemo6 {
+staticclass Inner{
void show(){}
          }
public void method(){
this.new Inner().show();//可以
     }
public static void main(String[] args) {//static 不允许 this
This.new Inner().show();//错误,Inner 类需要定义成 static
  } 
}
  • 面试3
interface Inter{
void show();
}
class Outer{//通过匿名内部类补足 Outer 类中的代码。
public static Inter method(){
return new Inter(){
public void show(){}
};
} }
class InnerClassDemo7 {
public static void main(String[] args) {
Outer.method().show(); 
/*
Outer.method():意思是:Outer 中有一个名称为 method 的方法,而且这个方法是静态的。
Outer.method().show():当 Outer 类调用静态的 method 方法运算结束后的结果又调用了 show 方法,意
味着:method()方法运算完一个是对象,而且这个对象是 Inter 类型的

/*
function (new Inter(){
public void show(){}
}); //匿名内部类作为方法的参数进行传递。
}
public static void function(Inter in){
in.show();
} }

七. 异常

1. 异常概述

在这里插入图片描述

Java使用异常来表示错误,并通过 try ... catch 捕获异常;
Java的异常是 class ,并且从 Throwable 继承;
Error 是无需捕获的严重错误, Exception 是应该捕获的可处理的错误;
RuntimeException 无需强制捕获,非 RuntimeException (Checked Exception)需强制捕获,或者用 throws 声明;
不推荐捕获了异常但不进行任何处理。

在这里插入图片描述

异常:就是不正常。程序在运行时出现的不正常情况。其实就是程序中出现的问题。这个问题按照面向对象思想进行描述,并封装成了对象。因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是将这些信息进行封装。异常就是 java 按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。

  • 属于lang包下java.lang.Throwable:
    • Throwable:可抛出的
    • Error:错误,一般情况下,不编写针对性的代码进行处理,通常是 jvm 发生的,需要对程序进行修正。
    • Exception:异常,可以有针对性的处理方式
      无论是错误还是异常,它们都有具体的子类体现每一个问题,它们的子类都有一个共性,就是都以父类名才作为子类的后缀名

这个体系中的所有类和对象都具备一个独有的特点;可抛性
可抛性的体现:就是这个体系中的类和对象都可以被 throwsthrow 两个关键字所操作

2. 异常的出现

在计算机程序运行的过程中,总是会出现各种各样的错误:

  1. 有一些错误是用户造成的,比如,希望用户输入一个 int 类型的年龄,但是用户的输入是 abc :
// 假设用户输入了abc: 
String s = "abc"; int n = Integer.parseInt(s); // NumberFormatException!(数字格式异常)
  1. 程序想要读写某个文件的内容,但是用户已经把它删除了:
// 用户删除了该文件:
 String t = readFile("C:\\abc.txt"); // FileNotFoundException!(文件未创建异常!)

还有一些错误是随机出现,并且永远不可能避免的。比如:
网络突然断了,连接不到远程服务器;
内存耗尽,程序崩溃了;
用户点“打印”,但根本没有打印机;
……
所以,一个健壮的程序必须处理各种各样的错误。
所谓错误,就是程序调用某个函数的时候,如果失败了,就表示出错。

  • 调用方如何获知调用失败的信息?:
    • 方法一:约定返回错误码。
      例如,处理一个文件,如果返回 0 ,表示成功,返回其他整数,表示约定的错误码
int code = processFile("C:\\test.txt"); 
if (code == 0) { 
// ok: 
        } else { // error: switch (code) {
           case 1: // file not found: 
           case 2: // no read permission: default: // unknown error: 
    } 
}

因为使用 int 类型的错误码,想要处理就非常麻烦。这种方式常见于底层C函数

  • 调用方如何获知调用失败的信息?:
    • 方法二:在语言层面上提供一个异常处理机制。
      处理方式有两种:1、捕捉;2、抛出。
  1. 捕捉
    异常是一种 class ,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕
    获,这样就和方法调用分离了

    • try {
      需要被检测的代码;
      } catch(异常类 变量名){
      异常处理代码;
      } fianlly{
      一定会执行的代码;
      }

catch (Exception e) { //e 用于接收 try 检测到的异常对象。
System.out.println(“message:”+e.getMessage());//获取的是异常的信息。
System.out.println(“toString:”+e.toString());//获取的是异常的名字+异常的信息。
e.printStackTrace();//打印异常在堆栈中信息;异常名称+异常信息+异常的位置。

注意 finally 有几个特点:

  1. finally 语句不是必须的,可写可不写
  2. finally 总是最后执行
    如果没有发生异常,就正常执行 try { … } 语句块,然后执行 finally 。如果发生了异常,
    就中断执行 try { … } 语句块,然后跳转执行匹配的 catch 语句块,最后执行 finally 。
    可见, finally 是用来保证一些代码必须执行的。
    某些情况下,可以没有 catch ,只使用 try ... finally 结构

使用 try … catch … finally 时

  1. 多个 catch 语句的匹配顺序非常重要,子类必须放在前面;
  2. finally 语句保证了有无异常都会执行,它是可选的;
    一个 catch 语句也可以匹配多个非继承关系的异常。

异常处理原则:功能抛出几个异常,功能调用如果进行 try 处理,需要与之对应的 catch 处理代码块,
这样的处理有针对性,抛几个就处理几个。
特殊情况:try 对应多个 catch 时,如果有父类的 catch 语句块,一定要放在下面。

  1. throw 和 throws 关键字的区别:
    • throw 用于抛出异常对象,后面跟的是异常对象;throw 用在函数内。
    • throws 用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws 用在函数上。

通常情况:函数内容如果有 throw,抛出异常对象,并没有进行处理,那么函数上一定要声明,否则编译失败。但是也有特殊情况。

  1. 异常分两种

    • 编译时被检查的异常,只要是 Exception 及其子类都是编译时被检测的异常。
    • 运行时异常,其中 Exception 有一个特殊的子类 RuntimeException,以及 RuntimeException 的子类是运行异常,也就说这个异常是编译时不被检查的异常。
  2. 编译时被检查的异常和运行时异常的区别
    编译被检查的异常在函数内被抛出,函数必须要声明,否编译失败。
    声明的原因:是需要调用者对该异常进行处理。
    运行时异常如果在函数内被抛出,在函数上不需要声明。
    不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。

  3. 定义异常处理时,什么时候定义 try,什么时候定义 throws 呢?
    功能内部如果出现异常,如果内部可以处理,就用 try;
    如果功能内部处理不了,就必须声明出来,让调用者处理。

3. 自定义异常:

  1. 概述
    当开发时,项目中出现了 java 中没有定义过的问题时,这时就需要我们按照 java 异常建立思想,
    将项目的中的特有问题也进行对象的封装。这个异常,称为自定义异常
  2. 例题
    对于除法运算,0 作为除数是不可以的。java 中对这种问题用 ArithmeticException 类进行描述。对于这个功能,在我们项目中,除数除了不可以为 0 外,还不可以为负数。可是负数的部分 java 并没有针对描述述。所以我们就需要自定义这个异常
  • 自定义异常的步骤
    1. 定义一个子类继承 Exception 或 RuntimeException,让该类具备可抛性。
    2. 通过 throw 或者 throws 进行操作。

异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。
在这里插入图片描述
这种情况,如果出现异常,并不处理,但是资源一定关闭,所以 try finally 集合只为关闭资源。
记住:finally 很有用,主要用户关闭资源。无论是否发生异常,资源都必须进行关闭。

System.exit(0); //退出 jvm,只有这种情况 finally 不执行。

当异常出现后,在子父类进行覆盖时,有了一些新的特点:

  • 当子类覆盖父类的方法时,如果父类的方法抛出了异常,那么子类的方法要么不抛出异常要么抛出父类异常或者该异常的子类,不能抛出其他异常。
  • 如果父类抛出了多个异常,那么子类在覆盖时只能抛出父类的异常的子集
    注意
    如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的如果子类的覆盖的方 法中出现了异常,只能 try 不能 throws
    如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过 throw
    抛出 RuntimeException 异常或者其子类,这样,子类的方法上是不需要 throws 声明的

常见异常
1、脚标越界异常(IndexOutOfBoundsException)包括数组、字符串;空指针异常(NullPointerException)
2、类型转换异常:ClassCastException
3、没有这个元素异常:NullPointerException
4、不支持操作异常;
异常要尽量避免,如果避免不了,需要预先给出处理方式。比如家庭备药,比如灭火器

八. 包

1. 定义

包用 package 关键字。

2. 如何使用

1:对类文件进行分类管理。
2:给类文件提供多层名称空间。

  • 如果生成的包不在当前目录下,需要最好执行 classpath,将包所在父目录定义到 classpath 变量中即可。一般在定义包名时,因为包的出现是为了区分重名的类。所以包名要尽量唯一。怎么保证唯一性呢?可以使用 url 域名来进行包名称的定义。
  • package pack;//定义了一个包,名称为 pack。 注意:包名的写法规范:所有字母都小写。
    //package cn.itcast.pack.demo;
  • 类的全名称是 包名.类名
  • 编译命令:javac –d 位置(.当前路径) java 源文件 (就可以自动生成包)
    包是一种封装形式,用于封装类,想要被包以外的程序访问,该类必须 public;
    类中的成员,如果被包以外访问,也必须 public;
  1. 包与包之间访问可以使用的权限有两种:
  • public
  • protected:只能是不同包中的子类可以使用的权限。
    在这里插入图片描述
  1. Import - 导入:
    类名称变长,写起来很麻烦。为了简化,使用了一个关键字:import,可以使用这个关键字导入指定包中的类。

记住:实际开发时,到的哪个类就导入哪个类,不建议使用

import packa.;//这个仅仅是导入了 packa 当前目录下的所有的类。不包含子包。
import packa.abc.;//导入了 packa 包中的子包 abc 下的当前的所有类
如果导入的两个包中存在着相同名称的类。这时如果用到该类,必须在代码中指定包名

常见的软件包
java.lang : language java 的核心包,Object System String Throwable jdk1.2 版本后,该
包中的类自动被导入。
java.awt : 定义的都是用于 java 图形界面开发的对象。
javax.swing: 提供所有的 windows 桌面应用程序包括的控件,比如:Frame , Dialog, Table, List
等等,就是 java 的图形界面库。
java.net : 用于 java 网络编程方面的对象都在该包中。
java.io : input output 用于操作设备上数据的对象都在该包中。比如:读取硬盘数据,往硬盘写
入数据。
java.util : java 的工具包,时间对象,集合框架。
java.applet: application+let 客户端 java 小程序。server+let --> servlet 服务端 java小程序。

jar :java 的压缩包,主要用于存储类文件,或者配置文件等。
命令格式:jar –cf 包名.jar 包目录
解压缩:jar –xvf 包名.jar
将 jar 包目录列表重定向到一个文件中:jar –tf 包名.jar >c:\1.txt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发热的嘤嘤怪(2003计科胜胜同学)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值