Java学习之路-java基础

338 阅读12分钟

今天就复习一下java基础吧,在这里记录一下

java注释

java 三种注释:单行注释|多行注释|文档注释

java语言的特点

java最初的开发商为SUN,2007年被Oracle收购

简单易学的、面向对象的、跨平台(一次编译,到处运行)、安全的、多线程的、分布式的

虚拟机 跨平台个人理解是.class文件在不同的平台上有着对应的运行,也就是不同平台上有着不同的jdk虚拟机。所以也就是常说的,不是java语言本身具备跨平台,而已java虚拟机跨平台?

一、数据类型与运算符

1、标识符

语言中相关对象名称的命名规则要求;java要求名称只能包含:字母、数字、下划线(_ )及$符号,并且不能以数字开始;同时标识不能与 java语言中内置的关键字重名;

变量名、函数名 :需要尊守camel命名法

类名、接口名、枚举 :需要尊守Pascal命名法

camel命名法:要求名称首字母小写,后每个单词首字符大写;

Pascal命名法:要求名称首字母大写,后每个单词首字符大写;

2、常量与变量

变量:内存中的一块空间;怎么访问?

java语言中的变量分为局部变量与全局变量( 成员变量);

局部变量:方法(函数)或者语句块 内声明的变量称为局部变量(包括方法的参数),对局部变量,在使用时需要有数据(初使化 )

全局变量:方法外声明的变量(类中声明的变量); 全局变量可以不初使化(因为系统会赋默认值);

int : 0

String : null;

常量:不能改变的变量,在java中,声明常量,需要添加关键字:final (常量名称全大写)

3、数据类型

java语言中数据类型分为基础数据类型(值类型) 与 引用类型 (放到面向对象的语法课程中学习 )

基本数据类型:8种

整型(4个):byte(8位) short(16) int(32) long(64) ---- int 是整型的默认类型

浮点数(2个) float (32),double(64) --- double是浮点数的默认类型

字符型:char(16) 可以存汉字

布尔型:boolean(true|false);

4、数据类型转换

隐式转换:将一个小的数据类型赋值给大的数据类型会自动发生隐式转换;

显示转换:将一个大的数据类型赋值给小的数据类型需要做显示转换(需要程序员手动实现);强转程序运行时有可能会出问题(抛异常|得到一个无效的数据),也有可能不会出问题

5、运算符

与生活中接触的运算符基本一样;

算术运算符(+ ,- * / %, ++ ,--

关系运算符(> >= < <= != ==)

赋值运算符(=,+= -= *= /=)

逻辑运算符(&& || !)

位运算符(& | >> << >>> ) 了解 ;( 效率最高 )

二、流程控制

1、程序结构

语言中,设计者设计了三种结构:顺序结构、选择结构、循环结构;

2、选择结构

IF语句(三个版本)

IF(表达式){

}

IF(表达式){

}else{

}

if(表达式){

}else if(表达式){

}else if(表达式){

}else if(表达式){

}.....

else{

}

表达式:运算的结构为boolean类型 的值(true | false)

switch(表达式){

}

switch后的表达式运行的结构是一个值(int)

**结论:**switch效率最高,在实际应用中,能用switch语句 ,不要用IF语句

switch语句中的表达式支持 的数据类型 --byte,short int、String,enum(枚举)

break:一个是跳出(中断)循环,在switch语句中跳出switch语句;

3、循环结构

for语句实现

for(计数器;退出条件;改计数器的值){

​ 循环体

}

while(表达式){

}

while循环中的表达式值为boolean类型的值;

三、方法与数组

1、方法基本概念

在面向过程的语言(C),没有方法的称呼(只有函数),在面向对象的语言中,只有方法,没有函数;

函数与方法功能一样:一段被命名的代码块(实现某一功能),方法是可以被调用的(不受次数限制)

C语言:组织程序是模块化思想(每一个模块一般对应一个函数或者多个函数,在通过一个文件组织一起)

方法:在面向对象语言中,只是表达当前对象的行为

方法语句:

【修饰符】返回值 方法名(【参数列表.....】){

方法体

}

main方法|main函数
public static void main(String[] args) {
    //程序运行的入口
}
2、学会方法封装

学会通过方法封装某一个业务功能,并知道此方法在设计要不要提供返回值以及方法的参数

3、方法重载(overload)

重载:方法名相同,参数的类型、数量、或者顺序不同的一组方法称为重载方法;

:重载与返回值无关(不能根据返回值的不同来判断是不是重载方法)

4、方法递归

一般情况:方法的使用是在一个方法中调用另一个方法

**递归:**方法中有一条语句直接或者问题调用方法本身,称为方法的递归调用;递归是程序中的一种算法(一些问题使用递归解决非常方便,简单,也比较好理解) ,递归就是从已知推未知

凡是循环能实现的功能,通过递归都可以实现;

递归需要有出口:没有出口递归本质就是一个死循环(Exception java.lang.StackOverflowError),所以递归需要有出口;

经验: 首先写一个方法(一般是有参的 有返回值的),在方法内部从已知条件开始写;(递归出口)

5、方法参数

参数难点:基本数据类型的参数、引用类型的参数,在给参数赋值时,参数值是不一样的;

基本数据类型:数据是存放在机内存的栈区,基本数据类型的变量在传递时,传递的是值的副本,对传递后的变量(形参)的修改不会影响原变量的值

引用类型:数据是存放在内存的堆区(引用类型的变量中存放的是地址 -- 堆区的内存地址),所以引用类型变量在传递时,传递的是地址,所以会导制多个变量(引用)同时指向堆区同一空间的数据,任意一个变量都可以访问此空间的数据(任意变量可以读此空间的数据,也可以改此空间的数据)

6、数组

数组:是具有相同类型的批量数据的集合;数组特点:元素是连续存放的(通过下标可以访问数组元素),数组大小一旦定义,不能修改(定义数组需要确认容器大小),元素是有下标的,下标从0开始,其中length属性返回的是数组的长度(元素数量);

一维数组 | 二组数组 | 多维数组

问题1:声明数组

类型[] 数组名 = new 类型[长度];

String[] users = new String[10];
int[] intArray = new int[10];

数组在创建时如果没有初使化,程序在运行时会自动给默认值;

byte short int long --- > 0

double,float --> 0.0

char --> 空格

boolean -- > false;

其它类型(引用类型) -- > null

类型[] 数组名 = new 类型[] { };

double[] doubleArray = new double[] {1.0,2.0,3.0,4.0,5.0};

类型[] 数组名 = { };

char[] charArray = {'a','b','c','d'};

4四种排序

冒泡法排序:相邻元素的比较最确一个最大或者最小

int[] arr = {4,2,1,10,9};
for(int i=0;i<arr.length-1;i++) { //控制比较的伦次;
    System.out.println("第" + (i+1) +"伦次");
    for(int j=0;j<arr.length-1-i;j++) { //控制相邻元素比较;
        if(arr[j] > arr[j+1]) {
            //交换;
            int tmp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = tmp;
        }
    }
}

**选择法排序:**每一次从数组中找到一个最大或者最小元素,再和某一个位置的元素交换;

public static void selectionSort(int[] arr) {
    //n个元素,只需n-1伦次就能确定一个有序的数组序列;
    for(int i=0;i<arr.length-1;i++) { //控制比较的伦次;
        //{4,2,1,10,9};
        int minIndex = i;// i =0;
        for(int j=i+1;j<arr.length;j++) { //能找到一个最小的元素下标;
             if(arr[j] < arr[minIndex]) {
                 minIndex =j;
             }
        }
        if(minIndex!=i) { //说明找到一个比minIndex小的下标;
            //交换元素;
            int tmp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] =tmp;
        }
    }
}

插入法排序:将元素放到一个已排好序的数组中;(将数组分成二部分,一部分为已排好序的,一部分为未排序)

int[] arr = {4,2,1,3,7,5,6,8,10,9};

第1伦:2,4,1,3,7,5,6,8,10,9

第2伦:1,2,4,3,7,5,6,8,10,9

public static void insertSort(int[] arr) {
    for(int i=1;i<arr.length;i++) { //控制伦次;
        int position = i; //position:要插入的位置;默认原位置 ;
        int insertElement = arr[i]; //要插入的元素;
        //写一段代码,得到要插入的位置(position)
        while(position > 0 && arr[position-1] > insertElement) {
            arr[position] = arr[position-1]; //将前一个替换后一个;
            position--;
        }
        arr[position] = insertElement; //在当前位置放要插入的元素;
    }
}

伦:1,2,3,4,7,5,6,8,10,9

**快速排序:**每一伦设一个基准数(第1元素),将数组分割成2部分,左侧是比基准数小的数列,右侧是比基准数大的数列;

6,1,2,7,9,3,4,5,10,8

第1伦 -- 1 :6,1,2,5,9,3,4,7,10,8

第1伦 -- 2 :6,1,2,5,4,3,9,7,10,8

在汇合点:重新设基准数:3,1,2,5,4,6,9,7,10,8

第2伦:分对数列基于第1个基准数左侧的数列重新再基于新基准数比对 |对右则也基于新基准数进行比对

public static void quickSort(int[] arr,int left,int right) {
    int i = left; //i,j是一个临时变量,存放每一次数序的比对范围
    int j = right;
    if(left > right) return;  //退出条件;
    int temp = arr[left]; //设置基准数;
    while (i != j) { // 不汇合;
        while (arr[j] >= temp && i < j) {
            j--;
        } // 从右向左找,找比基准数小的元素(记录元素的下标)
        while (arr[i] <= temp && i < j) {
            i++;
        } // 从左向右找,找比基准数大的元素(记录下标)
        if (i < j) { // 交换(右侧比基准数小的与左侧比基准数大的元素交换)
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
    //交换基准数;
    arr[left] = arr[i];
    arr[i] = temp;
    quickSort(arr, left, i-1); //对左侧再调用此方法继续排;
    quickSort(arr, i+1, right);
}

数组查询:遍历(就目前所做的项目,99%基本都可以使用此方式) | 二分查找(先排序)

在JDK中,排序与二分查找已实现 --- java.util.Arrays.sort | java.util. Arrays.binarySearch | Arrays.copyOf ; Arrays是JDK中数组操作的工具类 System.arraycopy(src, srcPos, dest, destPos, length);

public static int findElement(int[] arr,int element) {
    int index = -1;
    for(int i=0;i<arr.length;i++) {
        if(arr[i] == element) {
            index = i;
            break;
        }
    }
    return index;
}
public static int binarySearch(int[] arr,int element) {
    int index = -1;
    int startIndex = 0;
    int endIndex = arr.length-1;
    while(startIndex<=endIndex) {
        int middle =(startIndex + endIndex) / 2;
        if(arr[middle] == element) {
            index = middle;
            break;
        }else if(arr[middle] > element) {
            endIndex = middle -1;
        } else {
            startIndex = middle + 1 ;
        }
    }
    return index;
}

二维数组:数据结构是表结构(x,y)

问题1:声明数组

类型[第1维][第2维] 数组名 = new 类型[第1维长度][第2维长度]
int[][] arr =new int[2][3]; //总元素数量:2*3
for(int i=0;i<arr.length;i++) {
    for(int j=0;j<arr[i].length;j++) {
        System.out.print(arr[i][j] +"\t");
    }
	System.out.println();
}
类型[第1维][第2维] 数组名 = new 类型[][]{}
int[][] arr2 =new int[][] { {1,3},{4,5,6},{7,8,9,10} };
类型[第1维][第2维] 数组名 = {{},{},{}}

四、字符串(String)

1、理解字符串

字符串:字符集称为字符串**(存贮是字符数组**)

public final class String{
   private final char value[];
}

字符串特点:字符串一旦定义,不能修改 |字符串定义为一个final类(最终类),所以字符串是不能被继承的

声明字符串:有2种方式(不一样的)

方式一:字面量声明方式
String str ="hello,wolrd";
方式二:创建字符串对象
String s3 =new String("hello,world");

字面量方式创建的字符串,字符串放到字符串池中;new创建字符串对象,会在堆区申请空间,字符串放到堆内存中;

2、字符串操作

问题:需要记住String类设计的常用操作API (Application Program Interface)

符串的比对: equals|equalsIgnoreCase

问题:在字符串比较中,== 与 equals的区别

字符串连接:concat | String.valueOf

字符串分割:split 将字符串分割为字符数组;

**获取指定位置的字符:**charAt(index);

判断字符中是否包含某了子字符串:contains

判断字符以某一字符串开始|结束:startsWith | endsWith

将字符串转为字符数组:toCharArray()

将字符串转为大写|小写: toUpperCase| toLowerCase

**字符串截取:**subString

查找某一字符的下标: indexOf| lastIndexOf

去左右空格: trim

字符串替换:replace | replaceAll

判断字符串是否为空:isEmpty();

3、StringBuffer|StringBuilder

问题:String与StringBuffer区别?

String定义的是一个不可变的字符串,StringBuffer构建是一个可变的字符串对象;所以对字符串追加操作StringBuffer相对直接用String效率要高 ;

问题:StringBuffer与StringBuilder区别;

StringBuffer与StringBuilder都可以构建可变的字符串对象,两者的API一样 ;StringBuffer是线程安全的,StringBuilder是线程非安全的;

4、StringUtils工具类

在这里附带一个Apache网址: commons.apache.org/proper/comm…

挺多开源的代码,注意,使用需标注声明使用了人家代码,厚道一些。

五、类与对象

1、理解类

类代表一个种族(具有相同的特性及行为的一个群体),对象是基于此种族生成的一个具体的个体;在计算机的世界里,如果要表现出这个星球上的一个一个个体(物|对象),所有这些物所属的种族在计算机的世界中必须有(不分有生命和无生命);

种族(类) --- 物(对象)之间的关系 :是先有种族(类) ,然后再有对象;

2、类设计

【修饰符】 class 类名{

​ //类的成员 :成员属性 | 构造方法 | 成员方法 |初使化块

}

初使化块:每一次对象创建时都会执行;

创建对象

类型名 对象名 = new 构造方法(【参数列表】); 声明一个空对象;

3、构造方法

作用:创建对象时,给对象的属性初使化(赋一个默认值)

  • 构造方法一般为public (可以是其它封装)
  • 构造方法没有返回值(也不能加void)
  • 构造方法名与类名相同
  • 构造方法可以重载
  • 在设计类时,如果此类没有构造方法,在编译时,编译器会给类自动添加一个无参构造方法;当有构造方法时,编译时,不会添加无参构造方法;
  • 不能通过对象调用构造方法
4、封装

类成员封装:解决类成员的安全(数据安全 -- 有效|正确);

在JAVA语言中,封装有4个级别 :default(默认),private(私有的),protected(受保护的),public(公开的)

default(默认):在类的内部是可以访问的、本包中、在包外是不能访问的;

private : 只能在本类的内部访问 (本包中,包外都不能访问)

public:公开的(访问不受任何限制--本类内部、本包中、其它包中)

修饰符类的内部同一个包中子类任何位置
private×××
default××
protected√(子类的内部)×
public

面向对象语言三大特点:封装 、继承、多态

5、this关键字

**this :**表示本类的对象,this(【参数】) :类的构造方法

**注:**构造方法内如果调用其它构造方法,必须放在构造方法的第一条语句

6、包(package)

包:管理类的一个文件夹(一般在开发中,将同一性质的类放到同一个包中)

包的命名:一般采用网址的倒序(用.分割)

同一个包中的类是直接使用的,如果不在同一个包中,需要导入,如果不导入,需要使用全类名

了解一个jdk中常用的包

java.lang :基础类放在此包中(此包中的所有类及接口直接使用 --- 默认已导入)
java.util:java中工具类及集合在此包中(Scanner|Date|Arrays)
java.awt: GUI组件被放到此包中;
java.io :文件操作的相关类与接口放到此包中;
java.net :网络编程相关接口与类放在此包中;
java.sql:数据库操作的相关设计放在此包中;
javax.swing :GUI组件设计所放的包(是awt的升级)
......


导包:import 包.类;

7、static关键字

类的成员分成二种:静态成员 | 实例(对象)成员 -- 是通过对象来访问的;

static :静态的 (共有的 --- 本类的所有对象共有的成员),静态的成员数据不是存贮在堆区;静态成员的数据存放内存的方法区(开辟一个块空间 --- 静态区|共享区)

记录创建的对象数量;

静态成员的访问:建议 静态的成员访问静态的成员|实例访问实例的;虽然实例的成员可以访问静态的成员,但不建议这样做(传递的信息不明确),静态的成员一定是不能访问实例的;

小结类的实例成员:属性、构造方法、初使化块、实例方法

小结类的静态成员:属性、静态初使化块、静态方法;

静态初使化块 :是在类加载到内存中就运行,只运行一次;

**难点:**当类的所有成员都存时,在创建对象时,是一个怎样的流程;

在设计类(尤其是工具类),为了使用的方便,将类的成员做成静态的 ;

8、单例模式

模式:解决某一类问题的通用方案称为模式;软件开发中,设计的问题主要有23种,所以前辈给出23种模式;

单例模式:一个类只能创建一个对象;

懒汉模式
public class Singleton {
	private static Singleton singleton  =  null;  //
	private Singleton() {
	}
	public static Singleton newInstance() {
		if(singleton ==null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}
饿汉模式
public class Singleton {
	private static Singleton singleton  =  new Singleton();  //
	private Singleton() {
	}
	public static Singleton newInstance() {
		return singleton;
	}
}

六、继承与多态

1、继承

继承即拥有 --- 支配 --- 不劳而获;

分析:相似性质的类具有相同的一些特性与行为,需要在每一个类中单独提供 --- 效率低|工作量大(无意义)

解决:单独做一个基类(父类),此类定义共同属性或者行为(方法),其它只需要继承本类即可;

如果两个类构建了继承关系后:类的身份发生变化;

被继承的类:父类 | 基类

继承的类:子类 | 派生类;

JAVA的继承是单根继承(一个类的直接父类只能有一个),但可以层层继承;

1.1 extends: 实现继承
public class Horse extends Animal{
}
1.2 protected:受保护的级别的封装

protected:此封装级别为继承而设计,此封装级别子类可以访问父类的成员 ;

子类的内部(不管在同一个包中或不同的包中)都可以访问,但类的外部是不行的(不在同一个包)

1.3 super关键字

super:父类的对象; super([参数.....]) :父类的构造方法;

1.4 理解子类对象的创建[难点]

在创建子类对象时,会选调用父类的构造方法,创建一个父类的对象,默认,会调用父类的无参构造方法创建父类的对象(如果父类有无参构造方法,可以省去显示调用),如果父类没有设计无参构造方法,必须显示的调用父类的带参构造方法

每一个子类的对象中都含着一个父类的对象(如果父类有父类,继续创建父类的父类对象,直到Object类)

1.5 final关键字

final作用

  • 修饰变量,定义的是常量;
  • 修饰方法,方法不能被重写
  • 修饰类,类不能被继承

​ jdk中目前知道的不能被继承的类:java.util.Scanner | java.util.Math|java.lang.String|java.lang.System|java.lang.StringBuffer|java.lang.StringBuilder

1.6 向上转型与向下转型【难点】

子类继承某一个类 :构造了一个父子关系 (是一个 is a 的关系) ,对IS A关系的类,在定义对象时,可以 直接将子类的对象赋值给父类对象; ---- 向上转型(不需要手动处理,自动实现)

向上转型后,父类的对象只能访问获取类的成员,子类新添加的成员父类的对象是访问不了的;;

不能直接将父类对象赋值给子类对象(父类对象能代表它的任意一个子类对象),需要做强制转换 -- 向下转型

向下转型有可能出问题(父烦的对象本质不是当前对象的类型),也有可能不出问题(当前父类的对象的本质就是当前转型的对象类型),会异类型转换异常(ClassCastException)

判断对象的类型:instanceof

1.7 Object类

当一个类没有显示的指定从某一个类继承,那么此类就从Object类继承,Object类是JAVA语言中类层次的根;,Object类中定义的成员,每一个类身上都有(要能被继承下去)

需要熟悉Object类的设计

protected Object clone():如果某类提供clone()功能 ,此类需要实现Cloneable接口(标识接口),clone()得到的是一个新对象;

public boolean equals(Object) :对象比对(默认实现的比对地址)

public boolean equals(Object obj) {
        return (this == obj);
 }

String类对Object继承的equals方法进行重新实现了(实现了字符串的比对)

protected void finalize():被GC调用的;可以手动实现释放资源;

public Class<?> getClass():返回类的全路径名;

public String toString()

return getClass().getName() + "@" + Integer.toHexString(hashCode());

public int hashCode() :返回的对象地址(十进制)

notify|notifyAll :线程唤醒

wait:线程等待;

1.8 工具类
java.text.SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
java.util.Date now = new java.util.Date();
String strDate =  fmt.format(now);
java.util.Calendar cal = java.util.Calendar .getInstance();
int  year=  cal.get(Calendar.YEAR)
int  month=  cal.get(Calendar.MONTH)
2 多态(polymorphic)

问题:父类的行为满足不了子类的要求(不是子类要的) --- 怎么解决?;

解决:在子类中对继承的下来的方法重新设计

重写(override):子类对父类的方法进行重新实现(重新设计),重写的方法一般添加@Override注解

**多态:**父类行为的多面性称为多态 (子类重写造成的);

多态实现条件:

  • 要有继承
  • 要有重写(override)
  • 必须通过父类的对象调用(面向对象编程 -- 基类的对象)

七、抽象类与接口

1、抽象类

父类服务于子类的,父类的中如果有实现的方法(行为),在子类中可以直接用(不修改|不重写),就在父类中实现;如果父类的方法(行为)在字类中需要重写,可以在父类只定义方法,不提供方法的实现 --- 抽象方法;

抽象方法:只有方法的定义,没有方法的实现,在定义时需要添加一个关键字 -- abstract;

抽象类:包含抽象方法的类,称为抽象类(需要设计成抽象类) --- abstract

  • 定义抽象类关键字:abstract
  • 抽象类通常以父类出现
  • 抽象类是不能实例化的;
  • 抽象类应用:使用抽象类的子类 | 看此抽象类有没有静态成员(属性|方法)
  • 抽象类本质是类,所以普通类中有的成员,抽象类中都可以有;

问题:类与抽象类的区别

类与抽象类本质是一样的,都是类; 抽象类一般是以基类的身份出现的,服务于子类的,可以包含抽象方法,普通类不可以;抽象类是不可以实例化的,普通类正常是可以实例化;

模板方法模式:模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现.

public abstract class AbstractLogin {
	public final void login() {
		//第1步:验证;
		this.validate();
		//第2步:实现登录;
		this.userLogin();
		//第3步:记录日志;
		this.writeLog();
	}
	public abstract void validate();
	public abstract void userLogin();
	public abstract void writeLog();
}
2、接口

面向对象编程三个层次:具体类的对象 --- 父类的类对象(抽象类|普通父类)-- 父类的对象(接口的对象

**接口:**是对类的行为(方法)定制的一套标准、一套规范、一套约束;

方法约束|规范:返回值 | 方法名 | 方法的参数(类型,数量,顺序)

  • 定义接口:interface

  • 实现接口:implements (需要对接口中的所有方法都要实现,除非本类是抽象类)

  • 接口中的方法默认就是抽象的,在定义时abstract关键字可加可不加;(不加了)

  • 接口所有成员的封装默认为public;

  • 接口是不能实例化;

  • 一个类可以实现多个接口,但一个类只能有一个直接父类;

  • 接口成能定义的成员:方法|属性(静态常量 static final)

  • JAVA8对接口做了扩展:允许接口中定义静态方法与默认方法

**问题:**抽象类与抽口的区别?

抽象类的本质为类,接口的本质是给类的行为定制规范;
抽象类与接口都不能实例化;
定义抽象类用abstract关键字,定义接口用interface
一个类只能有一个父类,但可以实现多个接口
抽象类中除了有抽象方法外,还可以有普通类中有的所有类成员,但接口中只能有抽象方法与属性(jdk8做了扩展,可以有默认方法与静态方法)
.......