Java基础

本文详细介绍了Java语言的基础知识,包括语言发展史、Java环境配置、DOS命令、类和对象、数据类型、运算符、流程控制结构以及数组。特别讨论了Java的特点,如跨平台性、安全性、面向对象等,还涵盖了类、对象、构造方法、封装、继承、多态等面向对象编程概念。此外,文章还提到了Java的泛型、反射机制和JDBC简介,以及数据源的概念。

1. Java常识

1.1 语言的发展史

  • 机器语言
  • 汇编语言
  • 高级语言

1.2 Java语言介绍

发展历史:

创始人: 詹姆斯·高斯林

1991年,高司令带领Sun公司的工程师小组以C++为基础创建的这种语言,起初命名为Oak,橡树的意思,后来发现Oak是一种已有的计算机语言的名字,于是更名为Java

Java体系:

  • JavaSE(Java Standard Edition):标准版,定位在个人计算机上的应用

  • JavaEE(Java Enterprise Edition):企业版,定位在服务器端的应用

  • JavaME(Java Micro Edition):微型版,定位在消费性电子产品的应用上

Java语言特点:

  • 跨平台/可移植性
    这是Java的核心优势。Java在设计时就很注重移植和跨平台性。比如:Java的int永远都是32位。不像C++可能是16,32,可能是根据编译器厂商规定的变化。这样的话程序的移植就会非常麻烦。

  • 安全性
    Java适合于网络/分布式环境,为了达到这个目标,在安全性方面投入了很大的精力,使Java可以很容易构建防病毒,防篡改的系统。

  • 面向对象
    面向对象是一种程序设计技术,非常适合大型软件的设计和开发。由于C++为了照顾大量C语言使用者而兼容了C,使得自身仅仅成为了带类的C语言,多少影响了其面向对象的彻底性!Java则是完全的面向对象语言。

  • 简单性
    Java就是C++语法的简化版,我们也可以将Java称之为“C+±”。跟我念“C加加减”,指的就是将C++的一些内容去掉;比如:头文件,指针运算,结构,联合,操作符重载,虚基类等等。同时,由于语法基于C语言,因此学习起来完全不费力。

  • 高性能
    Java最初发展阶段,总是被人诟病“性能低”;客观上,高级语言运行效率总是低于低级语言的,这个无法避免。Java语言本身发展中通过虚拟机的优化提升了几十倍运行效率。比如,通过JIT(JUST IN TIME)即时编译技术提高运行效率。 将一些“热点”字节码编译成本地机器码,并将结果缓存起来,在需要的时候重新调用。这样的话,使Java程序的执行效率大大提高,某些代码甚至接待C++的效率。
    因此,Java低性能的短腿,已经被完全解决了。业界发展上,我们也看到很多C++应用转到Java开发,很多C++程序员转型为Java程序员。

  • 分布式
    Java是为Internet的分布式环境设计的,因为它能够处理TCP/IP协议。事实上,通过URL访问一个网络资源和访问本地文件是一样简单的。Java还支持远程方法调用(RMI,Remote Method Invocation),使程序能够通过网络调用方法。

  • 多线程
    多线程的使用可以带来更好的交互响应和实时行为。 Java多线程的简单性是Java成为主流服务器端开发语言的主要原因之一。

  • 健壮性
    Java是一种健壮的语言,吸收了C/C++ 语言的优点,但去掉了其影响程序健壮性的部分(如:指针、内存的申请与释放等)。Java程序不可能造成计算机崩溃。即使Java程序也可能有错误。如果出现某种出乎意料之事,程序也不会崩溃,而是把该异常抛出,再通过异常处理机制加以处理。

1.3 Java开发环境

参考:Java及Jdk 安装配置教程

1.4 常见DOS命令

DOS:Disk Operating System:

是Windows桌面操作系统出来前的操作系统,以纯命令的形式直接操作磁盘。

win + r 输入 cmd 打开DOS窗口

常见命令:

# 切换盘符 以D盘为例
d:
# 显示当前目录详细信息
dir
# 移到指定目录
cd path
# 当前目录
cd .
# 上级目录
cd ..
# 清屏
cls
# 切换历史命令
# 按上下箭头选择
# 补全命令
# tab
# 创建目录
md dirName
# 删除目录
rm dirName
# 复制文件
cd file newFilePath
# 删除文件
del fileName
# 查看本机IP
ipconfig
# 测试主机与目标主机是否连通
ping ip

1.5 class文件执行流程

*整体流程: .java–>*.class–>二进制码

DOS中执行Java程序

首先编译文件

javac *.java

注: 若发生乱码,请加上 -encoding utf8

再将编译后的字节码文件转换为二进制文件

java *

注: 若是执行使用开发工具编写的程序发生 错误: 找不到或无法加载主类报错,一般是程序带了包名,则在转换的时候也需要加上包名,或者加上-d选项,下面给出一个完整的执行Demo

package demo;
/**
 * @author:MMW
 * @time: 2021/8/21 23:57
 */
public class Test {
    public static void main(String[] args) {
        System.out.println("hello java");
    }
}

DOS:

E:\MyFiles\file>javac Test.java
E:\MyFiles\file>java Test
hello java

2. 数据类型

2.1 标识符和关键字

标识符

包,类,变量,方法…等等,java中只要是起名字的地方,那个名字就是标识符

标识符定义规则:

  • 允许组成: 数字 字母 下划线_ 美元符号$
  • 不允许: 1. 以数字开头 2. 使用Java中的关键字
  • 建议: 遵循驼峰命名法,见名知意
  • 特点: 大小写敏感

关键字

被JAVA语言赋予了特殊含义,用作专门用途的单词

特点: 关键字都是小写的

关键字参考: https://www.cnblogs.com/cosmosray/p/7441381.html

2.2 常量和变量

常量:

常量通常是指一个固定的值,例如: 1 , “a”,true 等

  • 字面常量: 1 , “a” true 等
  • 字符常量: 使用final修饰符修饰的,如 : PI

变量:

变量的本质是: 可操作性的存储空间 ,即变量的位置是固定的,但是里面放什么值是不固定的。

Java是一种强类型语言,每个变量都必须声明其数据类型。变量的数据类型决定了变量占据存储空间的大小

变量作为程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。变量在使用前必须对其声明, 只有在变量声明以后,才能为其分配相应长度的存储空间。

变量声明:

type var = value

变量使用

如果你只定义一个变量,没有给变量进行赋值的话,那么其实这个变量相当于没有定义

2.3 Java注释

Java中的注释与大部分程序设计语言一样,不会出现中可执行程序中。在Java中,有三种注释方式:

  • 单行注释
  • 多行注释
  • 文档注释
public class AnnotationDemo {
    public static void main(String[] args) {
        // 这是一个单行注释

        /*
           多行注释
           多行注释
           多行注释
         */

        /**
         * 文档注释,同样可以注释多行
         * 与第二种不同的是,这种注释可以自动生成文档
         */
    }
}

2.4 基本数据类型

2.4.1 前言

在Java中一切皆为对象,八种基本数据类型除外

在这里插入图片描述

可分为两大类

  • 基本数据类型
  • 引用数据类型

2.4.2 整数类型

在这里插入图片描述

public class IntegerDemo {
    public static void main(String[] args) {
        /*
         * 不同进制: 默认 十进制, 0 八进制, 0x 十六进制, 0b 二进制
         */
        int base_10 = 36;
        int base_8 = 036;
        int base_16 = 0x36;
        int base_2 = 0b11;

        /*
         * 定义 byte int short long
         * 整数默认是 int
         */
        byte num_byte = 126;          // 隐式转换
        short num_short = 129;        // 隐式转换
        int num_int = 129;            // ------
        long num_long = 12345678910L; // 超过范围需显示声明

    }
}

2.4.3 浮点类型

在这里插入图片描述

float类型又被称作单精度类型,尾数可以精确到7位有效数字,在很多情况下,float类型的精度很难满足需求。
而double表示这种类型的数值精度约是float类型的两倍,又被称作双精度类型,绝大部分应用程序都采用double类型。
float类型的数值有一个后缀F或者f ,没有后缀F/f的浮点数值默认为double类型。
也可以在浮点数值后添加后缀D或者d, 以明确其为double类型。

public class FloatDemo {
    public static void main(String[] args) {
        /*
         * 浮点类型的两种表现形式
         * - 十进制形式
         * - 科学计数法形式
         */
        double num_base10 = 3.1415926;
        double num_science = 31415926E-7;

        /* 
         * 浮点类型的定义
         * 注意: 浮点类型默认是 double 类型的, float需要加 f or F
         */
        float num_float = 3.1415926F;
        double num_double = 3.1415926;
    }
}

2.4.4 字符类型

char为字符类型,在内存中占2个字节

char 类型用来表示在Unicode编码表中的字符。Unicode编码被设计用来处理各种语言的文字,它占2个字节,可允许有65536个字符。

public class CharDemo {
    public static void main(String[] args) {
        /*
         * 定义字符变量
         */
        char ch1 = '梦';

        /*
         * char类型字符的本质: 整数
         * char类型我们看到的样子就是它本身的字面常量,但是底层在进行计算的时候,
         * 实际上是按照一个码进行计算的。这个码就是ASCII(Unicode兼容了ASCII码,Unicode的前128位置ASCII)
         */
        char ch2 = '2' + 2;
        System.out.println("ch2 = " + ch2); // 4  输出的是 50+2 即ascll码为52对应的unicode字符
        System.out.println("'2' + 2 = " + ('2' + 2)); // 52
    }
}

2.4.5 布尔类型

true

false

  • 在内存中占一位
  • 不能以 0,1代替
public class BooleanDemo {
    public static void main(String[] args) {
        /*
         * true 真 false 假 
         */
        boolean b1 = true;
        boolean b2 = false;
    }
}

2.4.6 类型转换

转换形式:

  • 自动类型转换
  • 强制类型转换
public class ConvertDemo {
    public static void main(String[] args) {
        /*
         * 类型级别:(按数据类型范围从低到高的)
         * byte--->short--->char-->int--->long--->float--->double
         * - 自动类型转换 低级别 --> 高级别
         * - 强制类型转换 高级别 --> 低级别
         */
        int num1 = (int)6.5; // 6  强制类型转换
        System.out.println("num1 = " + num1);
        double num2 = 6;    // 6.0 自动类型转换
        System.out.println("num2 = " + num2);

        /*
         *  当一个表达式中有多种数据类型的时候,要找出当前表达式中级别最高的那个类型,然后
         *  其余的类型都转换为当前表达式中级别最高的类型进行计算。
         */
        double num3 = 12+1294L+8.5F+3.81+'a'; //12.0+1294.0+8.5+3.81+97.0
        System.out.println("num3 = " + num3);
    }
}

2.5 运算符

算术运算符 关系运算符 赋值运算符 逻辑运算符 条件运算符

参考资料:

Java运算符

运算符优先级

2.5.1 算术运算符

public class ArithmeticOperatorDemo {
    public static void main(String[] args) {
        /*
         * 基本 + - * / %
         * 注意 : 3/2 和 3/2.0的区别
         */
        System.out.println(2*3);    // 6
        System.out.println(3/2);    // 1
        System.out.println(3/2.0);  // 1.5
        System.out.println(12%5);   // 2
        System.out.println(12%5.0); // 2.0

        /*
         * 加/拼接 运算符 +
         */
        System.out.println(+5);   // 5  表示正数
        System.out.println(3+3);  // 6  相加
        System.out.println(3+'2');// 53 相加

        /*
         * 自增++/自减--
         * 运算规则:(--同理)
         * ++单独使用的时候,无论放在前还是后,都是加1操作
         * 将++参与到运算中:看++在前还是在后,
         * 如果++在后:先运算,后加1   如果++在前,先加1,后运算
         */
        int num1 = 5; num1++;
        System.out.println(num1);   // 6
        System.out.println(num1++); // 6
        System.out.println(++num1); // 8
    }
}

2.5.2 赋值运算符

public class AssignmentoperatorDemo {
    public static void main(String[] args) {
        /* 
         * 赋值运算符  a opr b 等价于 a = a opr b
         */
        int a = 6;
        System.out.println(a+=2); // a = a + 2 = 8
    }
}

2.5.3 关系运算符

public class RelationaloperatorDemo {
    public static void main(String[] args) {
        /*
         * 关系运算符: >,<,>=,<=,==,!=
         * 关系运算符最终结果:要么是true要么是false
         */
        System.out.println(3>6); // false
        System.out.println(3<6); // true
    }
}

2.5.4 逻辑运算符

image-20210822020503014

进行逻辑运算的,运算符左右连接的都是 布尔类型的操作数,最终表达式的结果是布尔值:要么是true,要么false

短路现象

短路的意思就是惰性运算,当符号左边的式子已经可以确认最后结果时,符号右边的式子就不进行计算了。

public class LogicaloperatorDemo {
    public static void main(String[] args) {
        /*
         * 短路与是Java语言中的一个逻辑运算符,记作&&,与编程语言中的与(&)相似,但是具有短路性质:在使用&进行运算时,不论左边为true或者false,右边的表达式都会进行运算,
         * 而如果使用&&进行运算,当左边为false时,右边的表达式不会进行运算,因此&&被称为短路与。
         * 短路或是Java语言中的一个逻辑运算符,记作||,与编程语言中的或(|)相似,但是具有短路性质:在使用|进行运算时,不论左边为true或者false,右边的表达式都会进行运算,
         * 而如果使用||进行运算,当左边为true时,右边的表达式不会进行运算,因此||被称为短路或。
         */
        int i=8;
        System.out.println((5>7)&&(i++==2)); //false
        System.out.println(i);  //8
        int a=8;
        System.out.println((5>7)&(a++==2)); //false
        System.out.println(a); //9
        int m=8;
        System.out.println((5<7)&&(m++==2)); //false
        System.out.println(m); //9
        int b=2;
        System.out.println((5<7)&(b++==2)); //true
        System.out.println(b);  //3
        int c=2;
        System.out.println((5<7)&(++c==2)); //false
        System.out.println(c);  //3
    }
}

2.5.5 条件运算符

condition? value1:value2

condition为true,输出value1,否则输出value2

2.5.6 位运算符

参考资料:Java语言位运算符详解

public class BitoperationDemo {
    public static void main(String[] args) {
        /*
         * 按位异或: 相同为 0,不同为1
         * a^b = b^a
         * a^a=0
         * a^0 = a
         * a^b^b=a(常用于加密)
         */
        int a = 3;int b = 6;
        System.out.println(a^a);  // 0
        System.out.println(a^0);  // 3
        System.out.println(a^b^b);// 3

        /*
         * 左移 乘2^a
         * 右移 除2^a
         */
        System.out.println(2<<2); // 8
        System.out.println(8>>2); // 2
    }
}

3. 流程结构

3.1 程序流程结构

  • 顺序结构
  • 分支结构
  • 循环结构

3.2 分支结构

3.2.1 if单分支结构

// 伪代码
if(expression){
    // when expression is true 
}

执行流程如下:

3.2.2 if 多分支结构

// 伪代码
if(expression1){
    // when expression1 is true
}else if(expression2){
    // when expression2 is true
}else{
    // when none of the expression  above is true
}

执行流程如下:

在这里插入图片描述

3.2.3 swith 多值匹配

// 伪代码
swith(expression){
    case v1:
        // when expression == v1
    case v2:
        // when expression == v1
    [default: code block;]
}

执行流程如下:

在这里插入图片描述

swith 穿透现象:

switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果表达式的值与任一case值不匹配,则进入default语句(如果存在default语句的情况)

可用于swith比较的值类型

switch语句中case标签在JDK1.5之前必须是整数(long类型除外)或者枚举,不能是字符串,在JDK1.7之后允许使用字符串(String)。

3.2 循环结构

3.2.1 for循环

// 伪代码
for(初始化表达式;布尔表达式;迭代因子){
    循环体
}

执行流程说明:

  • 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
  • 然后,检测布尔表达式的值。如果为true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
  • 执行一次循环后,更新循环控制变量。
  • 再次检测布尔表达式。循环执行上面的过程。

执行流程如下:

在这里插入图片描述

3.2.2 增强for循环

// 伪代码
for(声明语句 : 表达式){
   // loop code here
}

声明语句:

声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。

表达式:

表达式是要访问的数组名,或者是返回值为数组的方法。

public class EnhancedForLoopDemo {
    public static void main(String[] args) {
        /*
         * 增强for循环
         */
        String[] names = {"Kobe","James"};
        for(String name:names){
            System.out.println(name);
        }
    }
}

3.2.3 while循环

// 伪代码
while(expression){
    // when expression is true
}

3.2.4 do while 循环

// 伪代码
do{
    // loop code here
}while(expression)

执行流程如下:image-20210822110754316

4. 数组

数组是java中 具有相同类型的数据的有序聚合,数组中每一个数据被称为元素,每个元素可以通过下标来访问。

4.1 一维数组

4.1.1 基本特点

  • 数组长度不可变
  • 数组可以存放任何数据类型,但是数组中元素类型必须相同
  • 下标索引 : 0-(length-1)
  • 数组属于引用数据类型

4.1.2 创建方式

  • 静态声明
// [] 位置可变
// 方式一
int[] arrName = {v1,v2,v3};
// 方式二
int[] arrName = new int[]{v1,v2,v3};
  • 动态声明
// []位置可变
int[] arrName = new int[3]

4.1.3 创建过程内存分析

2327137-20210401152147729-691666990

4.1.4 基本使用

public class ArrayDemo {
    public static void main(String[] args) {
        int arr[] = {1,2,3,4};
        /*
         * 数组的 length属性
         */
        System.out.println(arr.length); // 4

        /*
         * 数组元素的引用: 通过下标(从0开始) 
         */
        System.out.println(arr[1]);     // 获取第二个元素

        /*
         * 数组的遍历
         */
        for(int n:arr){
            System.out.println(n);
        }

        /*
         * 数组元素的默认初始值
         * 数组元素是整型:0
         * 数组元素是浮点型:0.0
         * 数组元素是char型:0 或 ‘\u0000’
         * 数组元素是boolean型:false
         * 数组元素是引用数据类型:null
         */
        int initValue_int[] = new int[3];           // 0
        float initValue_float[] = new float[3];     // 0.0
        char initValue_char[] = new char[3];        // '\u0000'
        boolean initValue_bool[] = new boolean[3];  // false
    }
}

4.2 二维数组

一个一维数组A的元素如果还是一个一维数组类型的,则次数组A称为二维数组。

4.2.1 创建方式

//静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
//动态初始化1
int[][] arr2 = new int[3][2];
//动态初始化2
int[][] arr3 = new int[3][];
//也是正确写法
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};

4.2.2 创建过程内存分析

image-20210822120648442

4.2.3 基本使用

public class TwoDimensionalArrayDemo {
    public static void main(String[] args) {
        /*
         * 数组定义
         */
        int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8}};

        /*
         * 元素引用
         */
        System.out.println("arr[0][0] = " + arr[0][0]);        // 1

        /*
         * length 属性
         */
        System.out.println("arr.length = " + arr.length);      // 3
        System.out.println("arr[2].length = " + arr[2].length);// 2

        /*
         * 二维数组遍历
         */
        for(int i=0;i<arr.length;i++){
            for(int j=0;j<arr[i].length;j++){
                System.out.println("arr[" + i + "][" + j + "] = " + arr[i][j]);
            }
        }
    }
}

4.3 数组应用

4.3.1 工具类 Arrays

java.util.Arrays:操作数组的工具类,里面定义了很多操作数组的方法

public class ArraysDemo {
    public static void main(String[] args){
        //判断两个数组是否相等
        int[] arr1 = new int[] { 1,2,3,4 };
        int[] arr2 = new int[] { 1,3,2,4 };
        System.out.println(Arrays.equals(arr1, arr2));//false

        //输出数组信息
        System.out.println(Arrays.toString(arr1));

        //将指定值填充到数组之中
        Arrays.fill(arr1,10);
        System.out.println(Arrays.toString(arr1));//[10,10,10,10]

        //对数组进行排序
        Arrays.sort(arr2);
        System.out.println(Arrays.toString(arr2));//[1,2,3,4]

        //二分法查找
        int[] arr3 = new int[]{-98,-34,2,34,66,79,106,210,333};
        int index = Arrays.binarySearch(arr3,210);
        System.out.println(index);
    }
}

4.3.2 数组相关问题

  • 最值问题
public static void main(String[] args){
    //实现一个功能:给定一个数组int[] arr = {12,3,7,4,8,125,9,45}; ,求出数组中最大的数。
    //1.给定一个数组
    int[] arr = {12,3,7,4,8,125,9,45,666,36};
    //2.求出数组中的最大值:
    //先找一个数上擂台,假定认为这个数最大:
    int maxNum = arr[0];
    for(int i=0;i<arr.length;i++){
        if(arr[i]>maxNum){
        maxNum = arr[i];
        }
    }
    System.out.println("当前数组中最大的数为:"+maxNum);            
}
  • 查询问题
public static void main(String[] args){
    //查询指定元素的位置--》找出元素对应的索引 
    //给定一个数组:
    int[] arr = {12,34,56,7,3,56,888};
    //           0  1  2  3 4  5
    //功能:查询元素888对应的索引:
    int index = -1; //这个初始值只要不是数组的索引即可
    for(int i=0;i<arr.length;i++){
        if(arr[i]==12){
            index = i;//只要找到了元素,那么index就变成为i
            break;//只要找到这个元素,循环就停止
        }
    }
    if(index!=-1){
        System.out.println("元素对应的索引:"+index);
    }else{//index==-1
        System.out.println("查无次数!");
    }
}
  • 增加问题
public static void main(String[] args){
    //功能:给定一个数组,在数组下标为2的位置上添加一个元素91
    //1.给定一个数组:
    int[] arr = {12,34,56,7,3,10,55,66,77,88,999,89};
    //2.输出增加元素前的数组:
    System.out.print("增加元素前的数组:");
    for(int i=0;i<arr.length;i++){
        if(i!=arr.length-1){
            System.out.print(arr[i]+",");
        }else{
             System.out.print(arr[i]);
        }
    }
    //3.增加元素
    int index = 1;//在这个指定位置添加 元素
    for(int i=arr.length-1;i>=(index+1);i--){
        arr[i] = arr[i-1];
    }
    arr[index] = 666;
    //4.输出增加元素后的数组:
   System.out.print("\n增加元素后的数组:");
   for(int i=0;i<arr.length;i++){
       if(i!=arr.length-1){
           System.out.print(arr[i]+",");
       }else{//i==arr.length-1 最后一个元素不用加,
           System.out.print(arr[i]);
       }
   }
}
  • 删除问题
public static void main(String[] args){
    //功能:给定一个数组,删除下标为2元素
    //1.给定一个数组:
    int[] arr = {12,34,56,7,3,10,34,45,56,7,666};
    //2.输出删除前的数组:
    System.out.println("删除元素前的数组:"+Arrays.toString(arr));
    //3.删除
    int index = 0;
    for(int i=index;i<=arr.length-2;i++){
        arr[i] = arr[i+1];
    }
    arr[arr.length-1] = 0;
    //4.输出删除后的数组:
    System.out.println("删除元素后的数组:"+Arrays.toString(arr));
}

5. 面向对象

5.1 面向对象与面向过程

面向对象

注重找“参与者”,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,注重的是事件的结果。考虑谁来做。

面向过程

当事件比较简单的时候,利用面向过程,注重的是事件的具体的步骤/过程,注重的是过程中的具体的行为,以函数为最小单位,考虑怎么做。

二者相辅相成,并不是对立的。解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间复杂的关系、方便我们分析整个系统;具体到微观操作,仍然使用面向过程方式来处理

5.2 类和对象

类是一些具有相同属性和行为的事物的集合

对象

对象是类的具体实现。

5.2.1 成员变量

成员变量用于定义该类或该类对象包含的数据或者说静态特征。作用范围是整个类体

成员变量和局部变量的区别

  • 定义位置不同

  • 作用范围不同

  • 是否有默认值不同

  • 在内存中位置不同

    ​ 成员变量:堆内存
    ​ 局部变量:栈内存

  • 生命周期不同

5.2.2 成员方法

成员方法

方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。

方法很类似于面向过程中的函数。

构造方法

构造方法是一种特殊的方法,其存在只有一个目的:用于创建和实例化对象。(本质上是给属性赋值)

class Person{
    Person(){
        System.out.println("default person constructor method");
    }
    public static void main(String[] args) {
        Person p = new Person();
    }
}
  • 构造方法无返回值
  • 默认自动创建无参构造,若创建有参则不自动创建无参
  • new对象就是调用的构造方法

基本数据类型和引用数据类型做实参的区别:

  • 引用数据类型被方法使用后被改变。传递的是地址值
  • 基本数据类型被方法使用后没被改变。传递的是复制值

5.2.3 static 关键字

static:静态的

可用于修饰: 属性、方法、代码块、内部类

被static修饰的方法和属性属于类方法和类属性,是类的所有实例化对象共享的,可以直接由类名进行调用

修饰属性: 静态属性

静态变量和成员变量的区别:

  1. 成员变量所属于对象。所以也称为实例变量。静态变量所属于类。所以也称为类变量。
  2. 成员变量存在于堆内存中。静态变量存在于方法区中。
  3. 成员变量随着对象创建而存在。随着对象被回收而消失。静态变量随着类的加载而存在。随着类的消失而消失。
  4. 成员变量只能被对象所调用 。
    静态变量可以被对象调用,也可以被类名调用。
    所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。

修饰方法:静态方法

  • 静态方法终不能有this关键字
  • 在静态方法中不能访问非静态方法
  • 在静态方法中不能访问非静态属性

注: 因为静态方法不需要创建对象即可调用,非静态成员需要创建对象才能调用,所以在静态方法中调用非静态成员是矛盾的。

修饰代码块:静态代码块
代码块执行顺序: 静态块–>构造块–>构造方法–>普通快

public class ExampleA {
    static {
        System.out.println("静态代码块执行");
    }

    {
        System.out.println("普通代码块执行");
    }

    public ExampleA() {
        System.out.println("无参构造执行");
    }

    void method(){
        System.out.println("方法执行");
    }
    public static void main(String[] args) {
        new CodeBlockDemo().method();

    }
}

输出:

静态代码块执行
普通代码块执行
无参构造执行
方法执行
Process finished with exit code 0

5.2.4 this关键字

this指代的是当前对象

作用:

1.修饰变量

当属性名字和形参发生重名的时候,或者 属性名字 和局部变量重名的时候都会发生就近原则,所以如果我要是直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候如果我想要表示属性的话,在前面要加上:this修饰,如果不发生重名问题的话,实际上你要是访问属性也可以省略this.

2.修饰方法

在同一个类中,方法可以互相调用,this.可以省略不写。

3.修饰构造方法

同一个类中的构造方法可以相互用this调用,注意:this修饰构造方法必须放在第一行

5.2.5 Package 和 import

Package作用

类似OS中的目录具有分类和隔离的作用

import的作用

导入其他的类

import * from package

静态导入(仅导入包中静态类)

import static * from package

注: lang包无需显示导入

5.3 OOP三大特性

5.3.1 封装

对java封装的理解

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露

封装的好处

提高代码的安全性

实现封装的步骤

1.属性私有化

private int x;

2提供方法和操作的方法

public int getX(){
    return x;
}
public void setX(int x){
    this.x = x;
}

注: 在封装方法中还可以添加限制条件用于控制外部访问权限

5.3.2 继承

继承是 is a 的关系

例如: 学生是一个人, 教师是一个人。

继承的好处

  • 提高了代码的复用性,父类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了
  • 提高了代码的扩展性
  • 为了以后多态的使用。是多态的前提。

继承语法和特点

语法:

public class Student extends Person(){
    /* code here */
}

特点:

  • 单根继承,多级继承,若无显示继承关系,则默认继承Object类。

  • 继承具有传递性

  • 子类构造自动调用父类构造

  • 可调用父类中的静态方法

访问修饰符

image-20210826010437514

super关键字

指代 父类的,可用于修饰属性、方法

修饰属性和方法

在子类的方法中,可以通过 super.属性 super.方法 的方式,显示的去调用父类提供的属性,方法。在通常情况下,super.可以省略不写:

在特殊情况下,当子类和父类的属性[方法]重名时,你要想使用父类的属性[方法],
必须加上修饰符super.,只能通过super.属性[super.方法]来调用

修饰构造方法

public class ExtendsDemo {
    public static void main(String[] args) {
        new CNY();
    }
}

class Money{
    public Money(){
        System.out.println("父类 构造");
    }
}

class CNY extends Money{
    public CNY(){
        // 实际上这里自动调用了父类构造
        //super();
        System.out.println("子类 构造");
    }
}

输出:

父类 构造
子类 构造
Process finished with exit code 0

在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存:
因为super修饰构造器要放在第一行,this修饰构造器也要放在第一行

方法重写 override

发生在继承的父子类中。当子类对父类提供的方法不满意的时候,要对父类的方法进行重写。

重写有严格的格式要求

子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。

重载和重写的区别:

  • 重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载
  • 重写:在不同的类中,子类对父类提供的方法不满意的时候,要对父类的方法进行重写。

注意:

1.不能重写父类的私有方法
2.父类的非静态方法不能重写为静态方法

image-20210826012900321

5.3.2 多态

多态的概念

多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。

多态跟属性无关,多态指的是方法的多态,而不是属性的多态

多态的好处

为了提高代码的扩展性,符合面向对象的设计原则:开闭原则(OCP原则)。

开闭原则(OCP):指的就是扩展是 开放的,修改是关闭的。

注意:多态可以提高扩展性,但是扩展性没有达到最好,以后我们会学习 反射

向上转型和向下转型

  • 向上转型 子类 --> 父类

向上转型时,只能调用在父类定义了的属性和方法,无法调用子类的特有属性和方法

父类名 对象名 = new 子类名();

  • 向下转型 父类 --> 子类

为了使用子类中特有方法和属性,需要对父类引用进行强制转换。
子类名 对象名 = (子类名)父类引用

5.4 抽象类和接口

5.4.1 抽象类

类是对现实事务的抽象

抽象类

抽象类就是对类的抽象

抽象类的定义

public abstract class AbstractClassDemo {
    public abstract void method1();   
    public void method2(){};
}

抽象类的继承

public class ExtendsAbstractDemo extends AbstractClassDemo{
    @Override
    public void method1() {
        System.out.println("实现抽象方法1");
    }
    @Override
    public void method2() {
        super.method2();
        System.out.println("重写方法2");
    }
}
  • 通过abstract定义的方法是抽象方法,它只有定义,没有实现。抽象方法定义了子类必须实现的接口规范;
  • 定义了抽象方法的class必须被定义为抽象类,从抽象类继承的子类必须实现抽象方法;
  • 如果不实现抽象方法,则该子类仍是一个抽象类;
  • 面向抽象编程使得调用者只关心抽象方法的定义,不关心子类的具体实现。

5.4.2接口

接口

在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力,如果一个抽象类没有字段,所有方法全部都是抽象方法,那么可以将这个类改为接口

interface

所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来(写不写效果都一样)。

定义接口

public interface Person {
    void run();
    String getName();
}

实现接口

public class Student  implements Person{
    @Override
    public void run() {
        System.out.println("student running");
    }

    @Override
    public String getName() {
        return "student0";
    }
}

接口继承接口

// 接口继承接口,扩展接口方法
public interface Man extends Person{
    void shave();
}

default方法

default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。

  • Java的接口(interface)定义了纯抽象规范,一个类可以实现多个接口;

  • 接口也是数据类型,适用于向上转型和向下转型;

  • 接口的所有方法都是抽象方法,接口不能定义实例字段;

  • 接口可以定义default方法(JDK>=1.8)。

6. 泛型 Generic

什么是泛型

集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。

泛型使用

 ArrayList<Integer> al = new ArrayList<Integer>(); // jdk1.7之前
 ArrayList<Integer> al = new ArrayList<>();  // <>  钻石运算符  jdk1.7之后

泛型的优点

在编译时期就会对类型进行检查

7. Java反射机制

反射

运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

具体过程:
在编译后产生字节码文件的时候,类加载器子系统通过二进制字节流,负责从文件系统加载class文件。
在执行程序(java.exe)时候,将字节码文件读入JVM中—>这个过程叫做类的加载。然后在内存中对应创建一个java.lang.Class对象–>这个对象会被放入字节码信息中,这个Class对象,就对应加载那个字节码信息,这个对象将被作为程序访问方法区中的这个类的各种数据的外部接口。
所以:我们可以通过这个对象看到类的结构,这个对象就好像是一面镜子,透过镜子看到类的各种信息,我们形象的称之为反射

获取类的反射的方式

public class GetClassDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();
        // 方式一: getClass()
        Class c1 = student.getClass();
        // 方式二: class属性
        Class c2 = Student.class;
        // 方式三: 通过类的全限定名
        Class c3 = Class.forName("OOP.Student");
        // 方式四: 利用类加载器
        Class c4 = Student.class.getClassLoader().loadClass("OOP.Student");
    }
}

其实,以上四种方式获取到的反射是同一个对象,因为类在内存中只会被加载一次

通过反射获取类中信息

属性 xxxFields()

方法 xxxMethods()

动态调用方法

MethodName.invoke(object o,args...)

通过反射获取类的实例化对象

object o = c.newInstance();

8. JDBC

8.1 jdbc介绍

Java Database Connective

JDBC就是使用java对数据库进行操作,其本质就是一套接口,具体实现由数据库厂商实现。

使用步骤

  1. 注册驱动,告知Java程序要操作的是什么数据库
  2. 获取驱动,开启JVM与数据库之间的通信
  3. 获取数据库操作对象
  4. 执行sql语句
  5. 处理查询结果集
  6. 释放资源
import java.sql.*;
public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/k1501db";
        String user = "root";
        String pwd = "admin";
        // 获取连接
        Connection connection = DriverManager.getConnection(url,user,pwd);
        // 获取执行对象
        Statement statement = connection.createStatement();
        // 执行sql
        String sql = "select xh,name,sex from student where xh < 200";
        // 处理查询结果集
        ResultSet resultSet =statement.executeQuery(sql);
        while(resultSet.next()){
            String xh = resultSet.getString(1);// 根据字段顺序
            String name = resultSet.getString("name");// 根据字段名
            String sex = resultSet.getString("sex");
            System.out.println("xh="+ xh + ",name=" + name + ", sex=" + sex);
        }
        // 释放资源
        statement.close();
        connection.close();
    }
}

8.2 数据源

1.JDBC连接池

数据库连接池是一些网络代理服务或应用服务器实现的特性,实现一个持久连接的“池”,池中是多个已经创建好的连接。允许其他程序、客户端来连接,这个连接池将被所有连接的客户端共享使用.

连接池可以加速连接,也可以减少数据库连接,降低数据库服务器的负载.

2.连接池的作用

•数据库资源得到重用
•减少数据库建立连接和释放的时间开销,提高系统响应速度
•数据库连接统一管理,避免资源泄露。

3.DataSource 数据源技术

数据源技术是Java操作数据库的一个很关键技术。数据源提供了一种简单获取数据库连接的方式,并能在内部通过一个池的机制来复用数据库连接,这样就大大减少创建数据库连接的次数,提高了系统性能。

image-20210828181940032

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值