Java基础学习记录(二)

内部类:
将一个类定义在另一个类的里面,对里面那个类就称为内部类
访问特点:
*内部类可以直接访问外部类的成员,包括私有成员
之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用格式 外部类.this
*而外部类要访问内部类中的成员必须要建立内部类的对象。

访问格式:
1.当内部类定义在外部类成员位置上,而且非私有,可以在外部其他类中,
可以直接建立内部类对象
格式
外部类名.内部类名 变量名 = 外部类对象.内部类对象
Outer.Inner in = new Outer().new Inner();

2.当内部类在成员位置上,就可以被成员修饰符所修饰
比如,private : 将内部类在外部类中进行封装
static : 内部类就具备了static的特性。
当内部类被static修饰后,只能直接访问外部类中static成员,出现了访问的局限

	  在外部其他类中,如何直接访问static内部类的非静态成员呢?
	  new Outer.Inner().function();
	  
	  在外部其他类中,如何直接访问static内部类的静态成员呢?
	   Outer.Inner.function();
	   
注意:当内部类中定义了静态成员,该内部类必须是static的。
	  当外部类中的静态方法访问内部类时,内部类也必须是static的

当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事务在使用外部事物的内容。

内部类定义在局部时,
1.不可以被成员修饰符修饰
2.可以直接访问外部类中的成员,因为还持有外部类中的引用
但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。
在这里插入图片描述
在这里插入图片描述

匿名内部类:
1.匿名内部类其实就是内部类的简写格式
2.定义匿名内部类的前提
内部类必须是继承一个类或者实现接口
3.匿名内部类的格式: new 父类或者接口{定义子类的内容}
4.其实匿名内部类就是一个匿名子类对象。
5.匿名内部类中定义的方法最好不要超过3个。

在这里插入图片描述

异常就是程序在运行时出现不正常情况。

异常由来:问题也是显示生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。
其实就是java对不正常情况进行描述后的对象体现。

对于问题的划分:两种:一种使严重的问题,一种非严重的问题。
对于严重的,java通过Error类进行描述
对于Error一般不编写针对性的代码对其进行处理

对于非严重的,java通过Exception类进行描述
对于Exception可以使用针对性的处理方式进行处理

无论error或者exception都具有一些共性内容
比如:不正常情况的信息,引发原因等。

异常体系:
Throwable
|–Error
|–Exception
|–RuntimeException
异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性。
也就是说可以被throw和throws关键字所操作
只有异常体系具备这个特点

2.异常的处理
java 提供了特有的语句进行处理
try
{
//需要被检测的代码
}
catch(异常类 变量)
{
处理异常的代码(处理方式)
}finally
{
一定会执行的语句
}

3.对捕获到的异常对象进行常见方法操作
String getMessage();获取异常的信息

在函数上声明异常。
便于提高安全性,让调用出进行处理。不处理编译失败

对多异常的处理。
1.声明异常时,建议声明更为具体的异常。这样处理的可以更具体。
2.对方声明几个异常,就对应有几个catch块,不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

建议在进行catch处理时,catch中一定要定义具体处理方式。
不要简单定义e.printStackTrace(),
也不要简单的就书写一句输出语句

在这里插入图片描述

因为项目中会出现特有的问题
而这些问题并未被java所描述并封装对象。
所以对于这些特有的问题可以按照java对问题封装的思想。
将特有的问题,进行自定义的异常封装

自定义异常

当在函数内部出现了throw抛出异常对象,那么就必须要给出对应的处理动作
要么在内部try catch处理
要么在函数上声明让调用者处理。

一般情况下,函数内出现异常,函数上需要声明

发现打印的结果中只有异常的名称,却没有异常的信息。
因为自定义的异常并没有自定义信息。

如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了
所以子类只要在构造时,将异常信息传递给父类通过super语句
那么就可以直接通过getmessage方法获取自定义的异常信息了。

自定义异常:
必须是自定义类继承Exception

继承Exception原因
异常体系有一个特点,因为异常类和异常对象都被抛出
他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点

只有这个体系中的类和对象才可以被throws和throw操作

Throws 和 throw 的区别
throws 使用在函数上
throw 使用在函数内

throws 后面跟的异常类,可以跟多个,用逗号隔开
throw 后面跟异常对象
Exception 中有一个特殊的子类异常RuntimeException 运行时异常

如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过
如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过

之所以不用在函数上声明,是因为不需要让调用者处理
当该异常发生,希望程序停止。因为再运行时,出现了无法继续运算的情况,希望停止程序后
对代码进行修正。

自定义异常时:如果该异常的发生,无法再继续进行运算,
就让自定义异常继承RuntimeException

对于异常分两种:
1.编译时被检测的异常。
2.编译时不被检测的异常(运行时异常,RuntimeException以及其子类)

finally代码块:定义一定执行的代码。
通常用于关闭资源。
在这里插入图片描述

异常在子父类覆盖中的体现
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类
2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常,就必须要进行try处理,绝对不能抛出。

非静态内部类中不可以定义静态成员
内部类中如果定义了静态成员,该内部类必须要被静态修饰
在这里插入图片描述
在这里插入图片描述
内部类只能访问被final修饰的局部变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对比13-16,可以看出13题是在函数中存在一个throw语句,也就是程序不一定执行异常抛出,所以可以通过编译。
在这里插入图片描述

包(package):
*对类文件进行分类管理
*给类提供多层命名空间
*写在程序文件的第一行
*类名的全称是 包名.类名
*包也是一种封装形式

为了简化类名的书写,使用一个关键字,import

Import导入的是包中的类。
定义包名不要重复,可以使用url来完成定义,因为url是唯一的。

Jar包
*Java的压缩包
*方便项目的携带
*方便于使用,只要在classpath设置jar路径即可
*数据库驱动,SSH框架等都是以jar包体现的。

String类

  • 字符串是一个特殊的对象
  • 字符串一旦初始化就不可以被改变
  • String str = “abc”
  • String str1 = new String(“abc”);
    有什么区别
    S1在内存中有一个对象
    S2在内存中有两个对象

String类复写了Object类中equals方法,该方法用于判断字符串是否相同

1.对于对象引用类型:“==”比较的是对象的内存地址
2.对于基本数据类型,比较的是它的值

String 类是用于描述字符串事物
那么它就提供了多个方法对字符串进行操作。

常见的操作
1.获取。
1.1 字符串中包含的字符数,也就是字符串的长度
int length():获取长度。
1.2 根据位置获取位置上的某个字符。
char charAt(int index):
1.3 根据字符获取该字符在字符串中位置。
int indexOf(int ch):返回的是ch在字符串中第一次出现的位置。
int indexOf(int ch, int fromIndex):从fromIndex指定位置开始,获取ch在字符串中出现的位置。

	int indexOf(String str):返回的是str在字符串中第一次出现的位置。
	int indexOf(String str, int fromIndex):从fromIndex指定位置开始,获取str在字符串中出现的位置。
	
	int lastIndexOf(int ch)	

2.判断
2.1 字符串中是否包含某一个子串
boolean contains(str):
特殊之处:indexOf(str):可以索引str第一次出现位置,如果返回-1,表示该str不在字符串中存在
所以,也可以用于对指定判断是否包含。
if(str.indexOf(“aa”)!=-1)

			而且该方法即可以判断,又可以获取出现的位置。
			
2.2 字符中是否有内容
	boolean isEmpty():原理就是判断长度是否为0."" null
2.3 字符串是否是以指定内容开头。
	boolean startsWith(str);
2.4 字符串是否是以指定内容结尾。
	boolean endsWith(str);
2.5 判断字符串内容是否相同。复写了Object类中的equals方法。
	boolean equals(str);
2.6 判断内容是否相同,并忽略大小写。
	boolean equalsIgnoreCase();

3.转换
3.1 将字符数组转成字符串
构造函数:String(char[])
String(char[],offset,count):将字符数组中的一部分转成字符串。

	静态方法:
			static String copyValueOf(char[]);
			static String copyValueOf(char[] data,int offset ,int count);
			
			static Stirng valueOf(char[]);
3.2 将字符串转成字符数组

3.3 将字节数组转成字符串
	String(byte[])
	String(byte[],offset,count);
3.4 将字符串转成字节数组
		byte[] getBytes();
3.5将基本数据类型转成字符串
	static String valueOf(int)
	static String valueOf(double)
	//3+"";//String.valueOf(3);

	特殊:字符串和字节数组在转换过程中,是可以指定编码表的
  1. 替换
    String replace(oldchar,newchar)

5.切割
String[] split(regex);

6.子串。获取字符串中的一部分
String substring(begin);
String substring(begin,end);

7.转换,去除空格,比较。
7.1将字符串转成大写或者小写
String toUpperCase();
String toLowerCase();
7.2将字符串两端的多个空格去除
String trim();
7.3对两个字符串进行自然顺序的比较
int compareTo(String)

StringBuffer是字符串缓冲区

是一个容器

  1. 而且长度是可变化的。

  2. 可以直接操作多个数据类型

  3. 最终会通过toString方法变成字符串
    C create U update R read D delete

  4. 存储
    StringBuffer append():将指定的数据作为参数添加到已有数据的结尾处
    StringBuffer insert(index,数据):可以将数据插入到指定index位置。

  5. 删除
    StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end
    StringBuffer deleteCharAt(index):删除指定位置的字符

  6. 获取
    char charAt(int index)
    int indexOf(String str)
    int lastIndexOf(String str)
    int length()
    String substring(int start,int end)

  7. 修改
    StringBuffer replace(start,end,string);
    void setCharAt(int index,char ch);

  8. 反转
    StringBuffer reserve

  9. 将缓冲区中指定数据存储到指定字符数组中
    void getChars(int srcBegin,int srcEnd ,char[] dst,int dstBegin)

StringBuffer是线程同步的
StringBuilder是线程不同步的
建议使用StringBuilder
升级三个因素:

  1. 提高效率
  2. 简化书写
  3. 提高安全性

基本数据类型对象包装类
byte (基本数据类型) Byte (引用数据类型)
short Short
int Integer
long Long
boolean Boolean
float Float
double Double
char Character

基本数据类型对象包装类的最常见作用,
就是用于基本数据类型和字符串类型之间做转换

基本数据类型转成字符串
基本数据类型+""
基本数据类型.toString(基本数据类型值)
如:Integer.toString(34);//将34整数变成“34”
字符串转成基本数据类型
xxx a = Xxx.parseXxx(String);
int a = Integer.parseInt(“123”);
double b = Double.parseDouble(“12.23”);
boolean b = Boolean.parseBoolean(“true”);
Integer i = new Integer(“123”);
int num = i.intValue();
十进制转成其他进制
toBinaryString();
toHexString ();
toOctalString();
其他进制转成十进制
parseInt(string,radix);
int x = Integer.parseInt(“110”,2);

JDK1.5版本以后出现的新特性
Integer x = new Integer(4);
Integer x = 4;//自动装箱。//new Integer(4)
x可以直接进行运算
x = x/x.intValue()/ + 2 x = 2:x进行自动拆箱。变成了int类型 再将和进行装箱赋给x
在这里插入图片描述

集合类

为什么会出现集合类?
面对对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作。就对对象进行存储,集合就是存储对象最常用的一种方式。

数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

集合框架

为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同
这个存储方式称之为:数据结构

将取出方式定义在集合的内部
这样取出方式就可以直接访问集合内容的元素
那么取出方式就被定义成了内部类
而每一个容器的数据结构不同
所以取出的动作细节不一样。但是都有共性内容判断和取出。那么可以写共性抽取

那么这些内部类都符合一个规则,该规则是Iterator。
如何获取集合的取出对象呢。
通过一个对外提供的方法
Iterator()
在这里插入图片描述
集合中只能添加对象,但是JDK1.5以后可以添加基本数据类型,因为基本数据类型有装箱拆箱动作

集合中存储的都是对象的引用(地址)

什么是迭代器呢?
其实就是集合取出元素的方式。

Collection
|–List: 元素是有序的元素可以重复,因为该集合体系有索引
|–ArrayList;底层的数据结构使用的是数组结构。特点:查询数据很快,但是增删稍慢。线程不同步
|–LinkedList;底层使用的是链表数据结构。特点:增删速度快,查询稍慢
|–Vector;底层是数组数据结构,是之前的版本,线程同步,被ArrayList替代。
|–Set: 元素是无序的,元素不可以重复

List:
特有方法。凡是可以操作角标的方法都是该体系特有的方法。


add(index ,element)
addAll(index,Collection);

remove(index);

set(index,element);

get(index);
subList(from,to);
listIterator();

List集合特有的迭代器,ListIterator 是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrModificationException异常

所以。在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的
只能对元素进行判断,取出,删除的操作
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator

该接口只能通过List集合的ListIterator方法获取

枚举就是Vector特有的取出方式。
发现枚举与迭代器很像
其实枚举和迭代是一样的。

因为枚举的名称以及方法的名称都过长。
所以被迭代器取代。

LinkedList:特有方法
addFirst();
addLast();

getFirst();
getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

removeFirst();
removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException

在JDK1.6出现了替代方法。
offerFirst();
offerLast();
添加元素

peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null

pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null

|–Set:元素是无序(取出存入的顺序不一定一致),元素不可以重复
|-- HashSet:底层数据结构是哈希表
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。

	注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法
|--TreeSet:

Set集合的功能和Collection是一致的。

Set:无序,不可以重复。
|–HashSet:数据结构是哈希表。线程是不同步的。

|--TreeSet:可以对Set集合中的元素进行排序。
		  底层数据结构是二叉树
		  保证元素唯一性的依据:
		  compareTo方法 return 0
		  
		  TreeSet排序的第一种方式:让元素自身具备比较性,
		   元素需要实现Comparable接口,覆盖compareTo方法
		  这种方式也称为元素的自然顺序,或者叫做默认顺序
		  
		  TreeSet的第二种排序方式。
		  当元素自身不具备比较性时,或者具备的比较性不是所需要的。
		  这时就需要让集合自身具备比较性。
		  在集合初始化时,就有了比较方式。

记住,排序时,当主要条件相同时,一定判断一下次要条件。

当元素自身不具备比较性,或者具备的比较性不是所需要的。
这是需要让容器自身具备比较性
定义了比较器,将比较器对象作为参数传递给TreeSet集的构造函数

当两种排序都存在时,以比较器为主
定义一个类,实现Comparator接口,覆盖compare方法

泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个安全机制。

好处
1.将运行时期出现问题ClassCastException,转移到了编译时期。
方便于程序员解决问题,让运行时期问题减少。
2.避免了强制转换麻烦。

泛型格式:通过<>来定义要操作的引用数据类型

在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型

其实<>就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可

什么是定义泛型类?
当类中要操作的引用数据类型不确定的时候
早期定义Object来完成扩展
现在定义泛型来完成扩展

泛型类定义的泛型,在整个类中有效,如果被方法使用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了

为了让不同方法可以操作不同类型,而且类型还不确定
那么可以将泛型定义在方法上

泛型定义在方法上时,放在返回值类型之前,修饰符之后

特殊之处:
静态方法不可以访问类上定义的泛型
如果静态方法操作的应用数据类型不明确,可以将泛型定义在方法上

?通配符。也可以理解为占位符
泛型的限定:
? extends E:可以接收E类型或者E的子类型。上限。
? super E:可以接收E类型或者E的父类型。下限。

Map集合:该集合存储键值对。一对一对往里存,而且要保证键
1.添加
put(K key,V value)
putAll(Map<? extends K,? extends V>m)
2.删除
clear()
3.判断
containsKey(Object value)
containsValue(Object key)
isEmpty()

4.获取
	get(Object key)
	size()
	values()
	
	entrySet()
	keySet()

Map
|–HashTable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0效率低
|–HashMap:底层是哈希表数据结构,允许使用null值和null键,该集合是不同的。JDK1.2效率高
|–TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序

和Set很像
其实Set底层就是使用了map集合。

map集合的两种取出方式:
1.Set keySet:将map中所有的键存入到Set集合,因为set具备迭代器。
所以可以迭代方式去取出所有的键,再根据get方法。获取每一个键对应的值

Map集合的取出原理,将map集合转成set集合。再通过迭代器取出

2.Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中,
而这个关系的数据类型就是:Map.

集合框架的工具类
Collections

集合变数组
Collection接口toArray方法

1.指定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。
长度为集合的size
当指定类型的数组长度大于了集合的size,就不会新创建数组,而是使用传递进来的数组。
所以创建一个刚刚好的数组最优。

	2.为什么要将集合变数组?
	为了限定对元素的操作(控制数量)

Arrays:用于操作数组的工具类
里面都是静态方法。

asList:将数组变成list集合

把数组变成list集合有什么好处?
可以使用集合的思想和方法来操作数组中的元素

	注意:将数组变成集合,不可以使用集合的增删方法。
	因为数组的长度是固定的。
	contains
	get
	indexOf()
	subList();
	如果增删。那么会发生UnsupportedOperationException

如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

高级for循环--------升级,简化书写
格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{

}
对集合进行遍历
只能获取元素,但是不能对集合进行操作。

迭代器除了遍历,还能进行remove集合中元素的动作。
如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的动作

传统for和高级for有什么区别呢?

高级for有一个局限性。必须有被遍历的目标。

建议在遍历数组的时候,还是希望使用传统for。因为传统for可以定义角标。

Static Import 静态导入

当类名重名时,需要指定具体的包名
当方法重名时,指定具体所属的对象或者类。

System:
描述系统一些信息。
获取系统属性信息:Properties getProperties

因为Properties是Hashtable子类,也就是Map集合的一个子类对象、
那么可以通过map的方法取出该集合中的元素。
该集合中存储都是字符串。没有泛型定义

JDK1.5版本出现的新特性

方法的可变参数
在使用时注意:可变参数一定要定义在参数列表的最后面

可变参数。
其实就是上一种数组参数的简写形式。
不用每一次都手动的建立数组对象。
只要将要操作的元素作为参数传递即可
隐式将这些参数封装成了数组


这些都是自己在学习时,纯手打的,可能结构上不是很清晰,有些散乱跳跃,不过大致是按照一定模块进行的,最后附上Java8API文件的压缩包方便大家查阅,提取码:ewcs。

发布了16 篇原创文章 · 获赞 4 · 访问量 333

猜你喜欢

转载自blog.csdn.net/qq_39197781/article/details/104569114