JAVA学习笔记 第四周

第四周

25 instanceof关键字

用于判断,左侧的引用是否属于右侧的类型

用于避免程序中引用数据类型转换异常

26 abstract 抽象类

1:抽象方法没有方法体,使用abstract关键字修饰,必须存在于抽象类中

abstract void fun();
//抽象方法必须为public  或者 protected 默认为public 

当一个类包含了抽象方法,那么这个类就是一个抽象类,必须用abstract修饰

在《JAVA编程思想》一书中,将抽象类定义为“包含抽象方法的类”

抽象类就是为了继承而存在的

2:抽象类不能new对象,必须通过new子类的方式创建对象(多态向上转型的方式)

3:子类必须重写父类所有的抽象方法,除非子类也是抽象类

4:抽象类中可以书写普通属性,普通方法,构造方法,用于给子类使用

5:抽象类依然可以实现多态,实现的方式与之前一致:父类作为形参和父类作为返回值

6:静态方法可以被继承,不能被重写

27 final关键字

27.1修饰属性

final:最终的

适用场景,可以用来修饰:

属性:

被final修饰的属性,称之为常量,常量要求全部大写,多个单词之间使用下划线分割

常量只能被赋值一次,常量通常(99%)在定义的时候赋值,或者在构造方法中赋值

这两种方法都是为了保证,在使用常量之前是有值的

publci class Test{
    final double PI=3.14;
}
public class Test1{
    final double PI;
    public Test1(){
        PI=3.14;
    }
    public Test1(int i){
        PI=3.14;
    }
}

以上代码的弊端是,每创建一个Test/Test1对象,都会在内存中定义一个PI,没必要存在多份。

所以可以加上static关键字修饰

此时常量只能被赋值一次,常量通常(99%)在定义的时候赋值。

public class Test{
    static final int A;
    static {
        A=1;
    }
}

27.2 修饰方法

被final修饰的方法不能被重写

27.3 修饰类

被final修饰的类不能被继承(extends)

28 接口 interface

28.1 特点

1:接口中的方法默认都是全局抽象方法,写不写都有public abstract修饰

2:接口不能直接new对象,必须通过new实现类(子类)的方式来创建(向上转型)

3:实现类(子类)必须重写接口中的所有方法(抽象方法),

除非子类也是抽象类或者接口

4:接口中

不能写:

普通属性(默认都是(并且只能是)全局静态变量,public static final),

普通方法(默认都是(也只能是)public abstract),方法不能有具体实现,没有方法体,也就是抽象方法,

构造方法

5:接口可以继承多个接口

6:实现类可以实现多个接口

允许一个类遵循多个接口

如果一个非抽象类遵循了接口,就必须实现接口中所有的方法

抽象类遵循了接口,可以不实现接口中的抽象方法

7:接口依然可以实现多态,实现方式与之前一致:接口(父类)作为形参和返回值

implements:

implements是一个实现接口用的关键字,用来实现接口中定义的抽象方法,要用到某个接口时,先继承,再重写接口方法实现该功能

implements,实现父类,子类不可以覆盖父类的方法或者变量。即使子类定义与父类相同的变量或者函数,也会被父类取代掉

//例如
public interface People{
    int a=1;
    public say();//public abstract
}
//但是接口没有方法体,只能通过具体的类去实现其中的方法体、
public class Chinese implements people{
    publci say(){
        sout("你好");
    }
} 

28.2 接口和抽象类的区别

1:抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

2:抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

3:接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

4:一个类只能继承一个抽象类,而一个类却可以实现多个接口

抽象类是对事物的抽象,即对类抽象。包括属性行为

接口是对行为的抽象

当你关注事物的本质,使用抽象类

当你关注某个功能,使用接口

29 常用类

29.1 枚举

枚举可以用于规范属性的值,使用枚举声明类

public enum Week{
    MON,TUE,WED,THUR,FRI,SAT,SUN
}
public class{
	//使用Week.调用,
    main(){
        Week A=Week.MON;
    }
    //也可以作为参数传入
    public void Flie(Week A){
        A.
    }
}

29.2 包装类

29.2.1 概念

每个基本数据类型 都有一个对应的包装类

byte short int long float double boolean char

Byte Short Integer Long Float Double Boolean Character

所有包装类都可将与之对应的基本数据类型作为参数,来构造他们的实例

除character类外,其他包装类可将一个字符串作为参数构造他们的实例

main{
    Byte b1=new Byte((byte)20);
    Byte b2 =20;
    Byte b3=new Byte(b2);
    Byte b1=new Byte("12");
    //数字默认都是int,要转为Byte首先要是byte类型,要手动下降
    
    //Boolean类	不区分大小写	除了true其他默认都是false
   	Boolean bl1 = new Boolean(true);
	Boolean bl2 = new Boolean("tRuE");
	Boolean bl3 = new Boolean("abc");
    
    Character ch1 = new Character('A');
}

29.2.2 包装类转换为基本数据类型

xxxValue()将包装类转换为基本数据类型

每一个包装类提供了这样一个方法

Boolean类构造方法参数为String类型时,若该字符串内容为true(不分大小写),则该Boolean对象表示true,否则表示为false

当Number包装类构造方法参数为String时,字符串不能为null,且该字符串必须可解析为相应的基本数据类型,否则不通过,运行时会抛出

NumberFormatException异常

		Byte b1 = new Byte("120");
		byte b = b1.byteValue(); // shift + alt + L 生成对应的变量接收方法返回值
		System.out.println(b);

29.2.3 基本类型转为包装类

valueOf() 每个包装类都提供valueOf方法,用于将基本数据类型转换为包装类型

		Integer i1 = Integer.valueOf(200);
		Integer i2 = Integer.valueOf("230");

29.2.4 基本类型转为字符串

toString():以字符串形式返回包装对象表示的基本数据类型(基本数据类型->字符串)

String str1 = Byte.toString((byte)20);
String str5 = Float.toString(3.14F);
String str7 = Boolean.toString(false);
String str8 = Character.toString('A');

29.2.5字符串转为基本数据类型

parseXXX() :把字符串转为相应的基本数据类型(character除外) 字符串->基本类型

byte b1 = Byte.parseByte("23");
int i1 = Integer.parseInt("200");

29.2.6 包装类面试题

Short Integer Long Character 包装类使用=赋值

且值的范围在-128-127时不会产生新对象,==比较为true

超出范围会new新的对象,==为true

Integer i1=127;
Integer i2=127;
sout(i1==i2)//true

    
Integer i3=128;
Integer i4=128;
sout(i3==i4)//false

29.3 自动装箱和拆箱

从JDK1.5开始,允许包装类和基本数据类型混合使用 减少代码量

装箱:将基本数据类型自动转换为包装类型

拆箱:将包装类型自动转换为基本数据类型

//装箱
Integer i1=20;
//拆箱
int i2=i1;

29.4 Math类

Math类,数学工具类,提供常用的数学计算方法和两个静态常量E PI

Math.E

Math.PI

Math.ceil(double a) 向上取整

Math.floor(double a) 向下取整

Math.round(double a) 四舍五入

Math.random() 随机数,0~1的小数

0~n

返回到多少的随机数n,就(Math.random() * n

29.5Random类

随机数类,丰富的方法

没有Short和byte

	Random ran1 = new Random();
		System.out.println(ran1.nextBoolean());
		System.out.println(ran1.nextDouble());
		System.out.println(ran1.nextFloat());
		System.out.println(ran1.nextLong());
		System.out.println(ran1.nextInt());
		System.out.println(ran1.nextInt(55));
	//只有int可以指定范围
	Random ran2 = new Random(11);
	Random ran3 = new Random(11);
	//11是种子,种子相同,得到的随机数相同
	//当同时有double 和float时,float由double决定

29.6 String类

length() :长度

equals():比较内容

equalsIgnoreCase():忽略大小写比较

toLowerCase():转换为小写

toUpperCase():转换为大写

concat():拼接字符串

indexOf():搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1

lastIndexOf():搜索最后一个出现的字符ch(或字符串value),如果没有找到,返回-1

substring(int index)提取从位置索引开始的字符串部分

substring(int beginindex, int endindex)提取beginindex和endindex之间的字符串部分 取头不取尾

trim()返回一个前后不含任何空格的调用字符串的副本

split()拆分字符串

endsWith() 判断字符串是否以某一个字符串结尾

startsWith()判断字符串是否以某一个字符串开头

replace()替换字符串

29.6.1 String类底层实现

String 类底层维护的是一个char数组

private final char value[];

并且这个数组是用final修饰,不可更改,所以String类的对象是不可变的

也就是说,字符串内容一旦确定是不可能发生改变的,任何对字符串改变的操作都将产生新的字符串

String a=“a”;

a+=“b”;

此时将产生三个字符数组,分别存储 a b ab

我们发现,不能对一个字符串内容进行频繁的改动,因为这样会产生很多的字符串对象,这些对象将占用内存空间

29.6.2 StringBuffer和StringBuilder的区别

这个都是可变的字符序列

private transient char[] toStringCache;

区别:

这两个依然属于字符串对象,只不过内容是可变的

StringBuffer 是线程安全的,多线程的,源自JDK1.0

StringBuilder 线程不安全,源自JDK1.5

29.6.3 为什么不能用==比较String对象

String a=“abc”;

String b=“abc”;

此时用==比较为true,按理说String作为引用数据类型比较的是地址,应该为false

但是String直接用=赋值的话,字符串对象将存在于常量池中。

第二次如果赋值相同的内容,会先去常量池中查找是否有相同的内容。

如果有,则将之前的地址重新赋值给当前变量,所以使用==比较为true

如果没有,则将当前内容存放在常量池中,等待下一次赋值。

String a=new String(“a”);

而用new关键字创建字符串对象,每一次都将开辟新的空间,所以使用==比较为false,而要用equals()比较,因为equals比较时转化为字符数组逐个比较。

30 集合

30.1 Collection接口

30.2 List接口

30.2.1 ArrayList

//定义:

//普通定义,不规定集合中的数据类型
ArrayList list1=new ArrayList();

//泛型定义,规定集合中的数据类型
ArrayList<包装类型> list2=new 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、ArrayList<包装类型>();

//常用方法:
ArrayList<Integer> list=new ArrayList<Integer>();
//add		增
list.add(数值);
//remove	删  位置	
list.remove(位置)
//set			改
list.set(位置,值)
//get			查
list.get(位置)
//size() 		长度
list.size();

三种遍历

ArrayList<Integer> list=new ArrayList<Integer>();

//普通for循环遍历
for(int i=0;i<list.size();i++){
    sout(list.get(i));
}
//迭代器遍历
Iterator<Integer> it1=list.iterator();
while(it1.hasNext()){
    sout(it1.next());
}
//增强for循环,底层实现依然是迭代器,是JDK1.5的新写法,依然是基于迭代器实现的
for( Integer i : list){
    sout(i);
}

底层实现

ArrayList 的特点:背背背

1有序,可以重复,可以为null,线程不安全

2底层实现是一个Object类型的数组

当我们调用无参构造方法,底层维护一个空数组,当我们第一次添加元素,将数组长度改为10

扩容为原数组的1.5倍

3查询,修改快,因为有下标

增加慢,因为需要扩容

删除慢,因为需要移动元素(数组)

30.2.2 Vector

常用方法和遍历和ArrayList相同

Vector和ArrayList的区别:

1 Vector是线程安全的,JDK 1.0

ArrayList线程不安全,JDK1.2

2 Vector 调用无参构造直接初始化一个长度为10的数组

ArrayList调用无参构造初始化一个空数组

3 Vector扩容2倍

ArrayList扩容1.5倍

30.2.3 LinkedList

常用方法:

LinkedList基于双向链表实现的集合

除了与ArrayList相同的增删改查方法外

还单独提供了用于操作头部和尾部的方法

操作方法:
addFirst();			添加到头
getFirst();			获得第一个
addLast();			添加到尾
getLast();			获得最后一个
removeFirst();		删除第一个
removeLast();		删除最后一个
isEmpty();			判空

底层实现

LinkedList的特点:

1 有序的,允许重复的,允许为null,线程不安全

2 根据下标查询,修改慢,因为不能直接查询到摸个元素,必须先查询相邻元素

3 增加和删除快,因为不需要扩容,不需要移动元素

get()方法优化:当我们根据下标查询LinkedList元素的时候

先对下标进行判断,如果下标是小于集合总长度中间值,从前往后查询

否则,从后往前找

对于LinkedLIst的三种遍历的速度

普通for(29秒)>>迭代器(0.9秒)=增强for(0.9秒)

鉴于LinkedList数据结构特点,不要使用普通的for循环遍历

30.3 Map接口

30.3.1 HashMap

由键值对组成,一一对应

常用方法

HashMap<String,String> map=new HashMap<String,String>();
//put(键,值);
map.put("CN","中国");
//get(键) 获取所给键的值
map.get("CN");
//remove(键) 有返回值
map.remove("CN");
//replace(旧键,新值)  改变所给键的值
map.replace("CN","中华民国");
//map.size();   长度
//map.clear();  清空
//map.isEmpty();判空

六种遍历

HashMap<String,String> map=new HashMap<String,String>();
//第一种,获取所有键
Set<String> keySet=map.keySet();
for(String key : KeySet){
    sout(key+"="+map.get(key));
}
//第二种,获取所有值
Collection<String> values=map.values();
for(String v : values){
    sout(v);
}
//第三种,获取所有键和值的组合
Set<Entry<String,String>> entrySet = map.entrySet();
for(Entry<String,String> entry : entrySet){
    sout(entry.getKey()+"="+entry.getValue());
}
//第四种,获取所有键的迭代器
Iterator<String> it1=map.keySet().iterator();
while(it1.hasNext()){
    String key=it1.next();
    sout(key+"="+map.get(key));
}
//第五种,获取所有值得迭代器
Iterator<Stirng> it2=map.values().iterator();
while(it2,hasNext()){
    sout(it2,next());
}
//第六种,获取所有键和值的组合的迭代器
Iterator<Entry<String,String>> it3=map.entrySet().iterator();
while(it3.hasNext()){
	//1
    Entry<String,String> entry=it3.next();
    sout(entry.getKey()+"="+entry.getValue());
    //2
    sout(it3.next());
}

数据结构

HashMap数据结构

JDK1.7 数组+单向链表

JDK1.8 数组+单向链表+红黑树(二叉排序树,左小右大)

HashMap存放数据过程:根据key所计算出来的hash值,决定当前元素在数组的位置,如果当前位置没有元素,则直接存放。

如果当前位置有元素,则向下延伸为单向链表,如果单向链表的长度超过8,将转换为红黑树

后序链表以后的元素减少到6以下,再将红黑树转换为单向链表。

扩容当数组的使用率达到75%,并且集合中的元素个数大于64,扩容两倍

30.3.2 Hashtable

HashMap与Hashtable的区别?

HashMap线程不安全,初始长度16,扩容2倍

Hashtable线程安全,初始数组长度11,扩容2倍+1

30.4 泛型

泛型:用于规范集合,或者接口,类中的数据结构

泛型书写位置:

接口上

形参

返回值

泛型通用的字母:

T Type 类型

E Element 元素

R Return 返回值

P Parameter 参数

K Key 键

V Value 值

以下代码目前供了解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值