day9
代码块
public class Person {
String name;
public Person(){
this.name = "pipi";
System.out.println("执行的是构造方法");
}
// 非静态代码块
{
System.out.println("执行的是非静态代码块 1");
}
{
System.out.println("执行的是非静态代码块 2");
}
{
System.out.println("执行的是非静态代码块 3");
}
public static void main(String[] args) {
new Person();
}
}
//非静态代码块是按照顺序执行的。
//output
//执行的是非静态代码块 1
//执行的是非静态代码块 2
//执行的是非静态代码块 3
//执行的是构造方法
一个类中初始化块若有修饰符,则只能被static修饰,称为静态代码块(static block),当类被载入时,类属性的声明和静态代码块先后顺序被执行,且只能被执行一次。
问:这里为什么不用this.age?
答:因为static是类方法,类加载的时候就创建了,this指的是对象,实例化以后才有,所以不能用。
public class Person {
String name;
static int age;
public Person(){
this.name = "pipi";
System.out.println("执行的是构造方法");
}
// 非静态代码块
{
System.out.println("执行的是非静态代码块 1");
}
{
System.out.println("执行的是非静态代码块 2");
}
{
System.out.println("执行的是非静态代码块 3");
}
// 静态代码块
static {
//这里只能使用静态static修饰的属性和方法
System.out.println("=====执行的是静态代码块======");
age = 1;
showAge();
}
public static void showAge(){
System.out.println(age);
}
public static void main(String[] args) {
new Person();
new Person();
}
}
/*
=====执行的是静态代码块======
1
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
*/
如果没有代码块呢?println()提示报错(java: 需要<标识符>),不能再类里直接sout。
非静态代码块:没有static修饰的代码块
- 可以有输出语句;
- 可以对类的属性声明进行初始化操作;
- 可以调用静态和非静态的变量或方法;
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行;
- 每次创建对象的时候,都会执行一次。且优先于构造函数执行。
静态代码块:用static修饰的代码块
- 可以有输出语句;
- 可以对类的属性声明进行初始化操作;
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性的和方法;
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行;
- 静态代码块的执行要优先于非静态代码块;
- 静态代码块只执行一次。
在实际开发中,static静态代码块用在初始化类的静态属性(static类型属性)
简单属性static int age =1;即可,但是类属性时,
public class Person2 {
// 变量声明
String name;
static int age = 1; // 简单属性static int age =1; 即可t
static Person2 tp = new Person2(); // 需要设置
public Person2(){
this.name = "pipi";
System.out.println("执行的是构造方法");
}
{
System.out.println("执行的是非静态代码块 1");
System.out.println("执行的是非静态代码块 2");
System.out.println("执行的是非静态代码块 3");
}
// 静态代码块
static {
//这里只能使用静态static修饰的属性和方法
age = 1;
showAge();
System.out.println("=====执行的是静态代码块======");
// 这里设置类属性
tp.name = "";
tp.age = 100;
}
public static void showAge(){
System.out.println("showAge return: " + age);
}
public static void main(String[] args) {
System.out.println("***** main中的实例化 *****");
new Person2();
new Person2();
System.out.println("***********************");
}
}
/*
* 以下结果中,可以看出先运行的部分是代码的变量声明
*
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
showAge return: 1
=====执行的是静态代码块======
***** main中的实例化 *****
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
***********************
*/
这里没听懂?
为什么非要这样写呢?
代码块在匿名类内部使用是无可替代的, 因为用不了构造方法,因为构造需要类名,匿名类没有类名,就不能用构造,所以需要其他方法来初始化各种属性,所以用代码块来初始化。(代码块在匿名的内部类中用来初始化属性)
java除了老版本中的东西以外,其他现存的这些东西,都是有作用的。而且是在某一个方式有不可替代的作用。
关键字final
在java中声明类、属性和方法时,可以使用关键字final来修饰,表示“最终”。
- final标记的类不能被继承。提高安全性、提高程序的可读性。e.g. String类、System类、StringBuffer类
- final标记的方法不能被子类重写。 e.g. Object类中的getClass()。
- final标记的变量(成员变量或局部变量)即为常量。名称大写,且只能被赋值一次;
e.g. final标记的成员变量必须在声明的同时、或在每个构造方法中、或代码块中显式赋值,然后才能使用。
e.g. final double PI = 3.14;
1、final修饰类
2、final修饰方法不能被子类重写
(下面这个写了两个类在同一个文件中,去掉final就可以运行了)。一个类里只能写一个类,如下会报错,这样放在一起只是为了方便。
3、final修饰常量(全局常量是什么意思?final static一起修饰变量,就是全局常量)
总结:
抽象类
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。
有时,将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类就做抽象类。
- 用abstract关键字来修饰一个类时,这个类叫做抽象类;
- 用abstract来修饰一个方法时,该方法叫做抽象方法。
抽象方法:只有方法的声明,没有方法的实现。以分号结束:abstract int abstractMethod (int a);
只要类中有一个抽象方法,那么这个类就必须是一个抽象类。
- 含有抽象方法的类必须被声明为抽象类。
- 抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
- 不能用abstract修饰属性、私有方法、构造方法、静态方法、final的方法。
抽象类举例
很奇怪,这些类竟然可以放在一个Animal.java文件中。
public abstract class Animal {
// 只要类中有个一个抽象方法,类就必须是一个抽象类
public abstract void test();
public abstract void move();
// public static void main(String[] args) {
// Dog d = new Dog();
// d.move(); //狗的移动方式是run...
// }
}
class Dog extends Animal{
//Class 'Dog' must either be declared abstract or implement abstract method 'test()' in 'Animal'
@Override
public void test() {
System.out.println("dog...");
}
@Override
public void move() {
System.out.println("狗的移动方式是run...");
}
}
class Fish extends Animal{
@Override
public void test() {
}
@Override
public void move() {
System.out.println("鱼的移动方式是swim...");
}
}
//抽象类可以继承抽象类
abstract class Bird extends Animal{
@Override
public void move() {
}
public abstract void test();// 只要类中有个一个抽象方法,类就必须是一个抽象类
}
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
d.move(); //狗的移动方式是run...
}
}
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
例如,在航运公司系统中,Vichle类需要定义两个方法分别计算运输工具的燃料效率和行驶距离。
问题:卡车Truck和驳船RiverBarge的燃料效率和行驶距离的计算方式完全不同。Vehicle类不能提供计算方法,但子类可以。
思考
Q1:为什么抽象类不可以使用final关键字声明?
A1:抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。
final是最终,它修饰的类是最终的类,不能被继承。而抽象类,如果想要使用,必须继承抽象类,实现那么抽象的方法。
Q2:一个抽象类中可以定义构造方法吗?
A2:抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。
抽象类不能实例化,new Vihicle()是非法的。
练习
public abstract class Emplyee {
public Emplyee() {
}
int id;
String name;
int salay;
public abstract void work();
}
class CommonEmployee extends Emplyee{
public void setCommonEmployeeInfo(int id, String name, int salay) {
super.id = id;
super.name = name;
super.salay = salay;
}
public void getCommonEmployeeInfo() {
System.out.println(super.id);
System.out.println(super.name);
System.out.println(super.salay);
}
@Override
public void work() {
System.out.println("这是一个普通员工");
}
}
class Manger extends Emplyee{
double bouns;
public void setMangerInfo(int id, String name, int salay, double bouns){
super.id = id;
super.name = name;
super.salay = salay;
this.bouns = bouns;
}
public void getMangerInfo(){
}
@Override
public void work() {
System.out.println("这是领导");
}
}
public class Test {
public static void main(String[] args) {
// Dog d = new Dog();
// d.move(); //狗的移动方式是run...
CommonEmployee ce = new CommonEmployee();
ce.work(); //这是一个普通员工
ce.setCommonEmployeeInfo(123,"poppy",15000);
ce.getCommonEmployeeInfo();//123
// poppy
// 15000
Manger m = new Manger();
m.work(); //这是领导
}
}
模板设计模式
模板方法设计模式
public abstract class Template {
public abstract void code();
public final void getTime(){
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("codef方法的执行时间是:" + (end-start));
}
}
class SubTemplate extends Template{
@Override
public void code(){
int k = 0;
for (int i = 0; i<1000; i++){
k += i;
}
System.out.println(k);
}
}
public class TestTemplate {
public static void main(String[] args) {
SubTemplate t = new SubTemplate();
t.getTime();
}
}
//499500
//codef方法的执行时间是:1
接口
另一种抽象方式:
- 有时必须从几个类中派生出一个子类,继承他们所有的属性和方法。但是java不支持多重继承。有了接口,就可以得到多重继承的效果。
- 接口interface是抽象方法和常量值的定义的集合。
- 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
- 实现接口类:class SubClass implements InterfaceA{ }
- 一个类可以实现多个接口,接口也可以继承其他接口。
接口的特点:
- 用interface来定义;
- 接口中的所有成员变量都默认是由public static final修饰的;
- 接口中的所有方法都默认是由public abstract修饰的;
- 接口没有构造方法;
- 接口采用多层继承机制。
举例:
代码实现
package course03;
public interface TestIn {
int ID = 1; //等同于public static final int ID = 1;
void test(); //public abstract void test();
}
package course03;
public interface TestInOne {
void test1();
}
package course03;
// 接口可以继承
public interface TestInTwo extends TestInOne {
// 必须要重写方法,否则报错
}
package course03;
//TestInImp1是个类,有了多个功能
public class TestInImp1 implements TestIn, TestInOne {
@Override
public void test() {
}
@Override
public void test1() {
}
}
- 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
- 接口的主要用途就是被实现类实现。(面向接口编程)
- 与继承关系相似,接口与实现类之间存在多调性。
举例: 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。
如果类没有实现接口所有方法,这个类就要定义为抽象类。
问题:接口和抽象类很相似,好像接口能做的事用抽象类也能做,为什么还要用接口呢?
为什么需要用接口(1)?
为什么需要用接口(2)?
父类Person类
public abstract class Person {
int age;
String name;
int sex;
public abstract void showInfo();
//抽象类中不用具体实现方法内容
}
唱歌、厨艺接口
/*
唱歌的接口
*/
public interface Sing {
void singing();
}
/*
* 厨艺的接口
* */
public interface Cooking {
void fry(); //炒菜
}
这个是描述会唱歌的厨子是一个老师的类
//一个类可以实现多个无关的接口Cooking\Sing
//接口Cooking\Sing
//实现类SCTeacher
public class SCTeacher extends Person implements Cooking, Sing {
String courese;//教的科目
public void setInfo(){
super.age = 27;
super.name = "pp";
super.sex = 1;
this.courese = "计算机";
}
// 重写父类的方法
@Override
public void showInfo() {
System.out.println("会唱歌,会做饭的老师的信息时:");
System.out.println("年龄:" + super.age);
System.out.println("姓名:" + super.name);
System.out.println("性别:" + super.sex);
System.out.println("课程:" + this.courese);
}
@Override
public void fry() {
System.out.println(super.name + "老师拿手的厨艺是炒菜");
}
@Override
public void singing() {
System.out.println(super.name + "老师擅长流行歌");
}
//调用
public static void main(String[] args) {
SCTeacher sct = new SCTeacher();
sct.setInfo();
sct.showInfo();
sct.fry();
sct.singing();
System.out.println("*********************");
// 接口的多态
Cooking c = new SCTeacher();
c.fry();
Sing s = new SCTeacher();
s.singing();
}
}
/*
会唱歌,会做饭的老师的信息时:
年龄:27
姓名:pp
性别:1
课程:计算机
pp老师拿手的厨艺是炒菜
pp老师擅长流行歌
*********************
null老师拿手的厨艺是炒菜
null老师擅长流行歌
Process finished with exit code 0
*/
与继承关系相似,接口与实现类之间存在多态性
上述代码,可用接口来接收实例对象
- 如果实现接口的类中,没有实现接口中的全部方法,必须将此类定义为抽象类。
- 接口也可以继承另一个接口,使用extends关键字。
- 类需要必须实现接口中的全部方法。
抽象类是对于一类事物的高度抽象,其中既有属性也有方法。接口是对方法的抽象,也就是对一系列动作的抽象。
当需要对一类事物抽象的时候,应该是使用抽象类,好形成一个父类。
当需要对一系列的动作抽象,就使用接口,需要使用这些动作的类去实现相应的接口即可。
工厂模式
建立一个返回值为BWM类的对象的抽象方法,该方法是生产汽车的,为后面具体的汽车空间提高方法。
接口内是一个(抽象)函数,返回值是BWM的类,下面具体实现这个函数。
以下实现:汽车生产工厂接口
这里修改并不影响:
这节课没有听懂。
内部类
一个类的内部再写一个类,可以调用类的其他变量,和方法一样?
- 在jiava中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
- Inner class一般用在定义它的类或语句块之间,在外部引用它时必须给出完整的名称。Inner class的名字不能与包含它的类名相同;
- Inner class可以使用外部类的私有数据,因为它是外部类的成员,同一个类的成员之间可以相互访问。而外部类要访问内部类的成员需要:内部类.成员 or 内部类对象.成员;
- 分类:成员内部类(static成员内部类和非static成员内部类)
- 局部内部类(不谈修饰符)、匿名内部类。
举例:
public class Test {
int i;
public int z;
private int k;
class A{
int i;
//class A里的set方法是为了要使用int i等三个属性的,使用属性需要方法。所以写此set方法。
public void setTestFileds(){
Test.this.i = 1;
Test.this.z = 2;
Test.this.k = 3;
}
// public void set(){
// this.i = 10;
// }
}
public void setInfo(){
//调用内部类
//内部类也是一个类啊
new A().setTestFileds(); // 外部的类要使用自己的内部类Class A的方法,得先new内部类的对象
System.out.println("*********");
// new A().set();
}
public void showInfo(){
System.out.println(this.i);
System.out.println(this.z);
System.out.println(this.k);
}
public static void main(String[] args) {
Test t = new Test();
t.setInfo();
t.showInfo();
}
}
/*
*********
1
2
3
* * */
内部类特性
内部类的最大作用是实现多重继承
Inner class作为类的成员:
- 可以声明为final的;
- 和外部类不同,inner class可以声明为private或protected;
- inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;
Inner class作为类:
- 可以声明为abstract类,因此可以被其他内部类继承;
【注意】非static的内部类中的成员不能声明为static的,只有在外部类或static的内部类中才可以声明static成员。
问题:内部类有什么用?外面也能写
内部类主要是解决java不能多重继承的问题。(接口是方法,类有其他属性,接口可以有属性吗?)
接口的属性在实现类中不能被使用,e.g.
内部类举例,文件结构如下:
import javax.crypto.spec.PSource;
public class Test2 {
public static void main(String[] args) {
A a = new A();
a.testB();
a.testC();
}
/*
A类中调用B类的变量:1000
这是重写之后的testB方法
父类B中的成员变量:1000
这是重写之后的testC方法
* */
}
/*
* 如果类A想同时获得类B和类C的方法,并且重写
* 可以使用内部类来变相的实现类的多重继承,可以同时继承多个类
* */
class A {
public void testB(){
System.out.println("A类中调用B类的变量:" + new InnerB().a);
new InnerB().testB();
}
public void testC(){
new InnerC().testC();
}
private class InnerB extends B{
int a = super.bb; // 可以这样赋值
@Override
public void testB() {
// super.testB();
System.out.println("这是重写之后的testB方法");
System.out.println("父类B中的成员变量:" + super.bb);
}
}
private class InnerC extends C{
@Override
public void testC() {
// super.testC();
System.out.println("这是重写之后的testC方法");
}
}
}
class B{
// 问题?继承的时候成员可以继承吗?可以super.
int bb = 1000;
public void testB(){
}
}
class C{
public void testC(){
}
}
面向对象总结
day10
异常
数组越界异常
空指针异常
java异常类层次
捕获异常
异常处理机制
try catch时没必要说明具体类型,即可。
抛出异常
举例
重写方法声明抛出异常的原则
子类重写父类的方法是,子类不能抛出比父类方法更大范围的异常。
举例
人工抛出异常
创建用户自定义异常类
一般轮不到自己写!
java集合概述
- 集合只能存放对象。比如你存一个int型数据1放入集合中,其实它是自动转换成Interger类后存入的,java中每一种基本类型都有对应的引用类型。
- 集合存放的是多个对象的引用,对象本身还是存放在堆内存中。
- 集合可以存放不同类型,不限数量的数据类型。
HashSet集合
hashset是set接口的典型实现,大多数时候使用set集合时都使用这个实现类。我们大多数时候说的set集合指的都是hashset。
hashset按hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
hashset具有以下特点:
- 不能保证元素的排列顺序
- 不可以重复
- hashset不是线程安全的
- 集合元素可以使用null
当向hashset集合中存入一个元素时,hashset会调用该对象的hashcode()方法来得到该对象的hashcode值,然后根据hashcode值决定该对象在hashset中的存储位置。
如果两个元素的equals()方法返回ture,但是它们的hashcode()返回值不相等,hashset将会把它们存储在不同的位置,但依然可以添加成功。
举例:不保证元素的排列顺序
不可重复指的是hashcode不相同。一般情况,equals和hashcode返回结果一致。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestHash {
public static void main(String[] args) {
Set seta = new HashSet();
seta.add(1); // 添加元素
seta.add("a");
System.out.println(seta); //[1, a]
seta.remove(1); //移除元素
System.out.println(seta); //[a]
//判断是否包含元素1
System.out.println(seta.contains(1)); //false
seta.clear(); //清空集合
System.out.println(seta); //[]
seta.add("b");
seta.add("c");
seta.add("d");
System.out.println(seta); //[b, c, d]
System.out.println("------------------");
//使用迭代器遍历集合
Iterator it = seta.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//for each迭代
//这个的意思是把set的每一个值取出来,赋值给obj,直到循环seta的所有值
for (Object obj : seta){
System.out.println(obj);
}
//b
//c
//d
//获取集合的大小
System.out.println(seta.size()); //3
//set集合不重复
seta.add("d");
seta.add(null);
System.out.println(seta); //[null, b, c, d]
}
}
hashset集合判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashcode()方法返回值也相等。
如果两个对象通过equals()方法返回ture,这两个对象的hashcode值也应该相同。
如果想要让集合只能存同样类型的对象,则使用泛型
import java.util.HashSet;
import java.util.Set;
public class TestHash {
public static void main(String[] args) {
//使用泛型,则集合只能存同样类型的对象
//比如指定string为集合的泛型,那么这个集合不能存string类型之外的
Set<String> set1 = new HashSet<String>();
set1.add("abc");
// set1.add(1); //error
//set2\set3 等价
Set set2 = new HashSet(); //Raw use of parameterized class 'Set'
Set<Object> set3 = new HashSet<Object>();
}
}
TreeSet集合
TressSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
TreeSet支持两个排序方法:自然排序和定制排序。默认情况下,采用自然排序。
自然排序
排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列。
- 如果this>obj,返回整数1;
- 如果this<obj,返回整数-1;
- 如果this=obj,返回整数0,则认为这两个对象相等;
- 必须放入同样类的对象。(默认会进行排序)否则可能会发生类型转换异常。我们可以使用泛型来进行限制。
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class TestTree {
public static void main(String[] args) {
Set<Integer> set1 = new TreeSet<Integer>();
//自然排序
set1.add(5);
set1.add(4);
set1.add(2);
set1.add(3);
System.out.println(set1); //[2, 3, 4, 5]
//遍历
//1 使用迭代器遍历集合
Iterator<Integer> it = set1.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//2 for each迭代集合,推荐使用这种
for (Integer i : set1) {
System.out.println(i);
}
//2
//3
//4
//5
set1.remove(5);
System.out.println(set1); //[2, 3, 4]
System.out.println(set1.contains(3)); //true
set1.clear();
}
}
集合是可以存各种数据的(类)
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
//把person对象存到TreeSet中,并且按照年龄排序
//Comparator接口的实现类
public class Person implements Comparator<Person> {
int age;
String name;
// 之前不懂为什么要有这个无参构造。
// 无参构造,为了Person comparator = new Person();
public Person(){
}
//构造函数
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public int compare(Person o1, Person o2) {
//年龄正排序
if (o1.age > o2.age){
return 1;
}else if(o1.age < o2.age){
return -1;
}else {
return 0;
}
}
public static void main(String[] args) {
Person p1 = new Person("A", 23);
Person p2 = new Person("B", 20);
Person p3 = new Person("C", 16);
Person p4 = new Person("D", 29);
//new Person(),没有无参构造,这句报错
Set<Person> setp = new TreeSet<Person>(new Person());
setp.add(p1);
setp.add(p2);
setp.add(p3);
setp.add(p4);
for (Person p: setp
) {
System.out.println(p.name + " " + p.age);
}
}
}
//C 16
//B 20
//A 23
//D 29
另一种实现,https://www.cnblogs.com/huhx/p/comparableAndcomparator.html
以上就是定制排序:如果需要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator接口的实现类对象。由该Comparator对象负责集合元素的排序逻辑。
List集合
- List代表一个元素有序、且可以重复的集合,集合中的每个元素都有其对应的顺序索引。
- List允许使用重复元素,可以通过索引来访问指定位置的集合元素。
- List默认按元素的添加顺序设置元素的索引。
- List集合里添加了一些根据索引来操作集合元素的方法。
import java.util.ArrayList;
import java.util.List;
public class TestList {
public static void main(String[] args) {
List<String> lista = new ArrayList<String>();
lista.add("b");
lista.add("c");
lista.add("d");
lista.add("a");
lista.add("a"); //可以重复
System.out.println(lista); //[b, c, d, a, a]
//通过索引来访问指定位置的元素集合
System.out.println(lista.get(2)); //d
//在指定索引下标的位置插入数据
lista.add(1,"f");
System.out.println(lista); //[b, f, c, d, a, a]
System.out.println("---------------------------------");
List<String> listb = new ArrayList<String>();
listb.add("123");
listb.add("456");
lista.addAll(2,listb); //在指定位置上插入新的集合
System.out.println(lista); //[b, f, 123, 456, c, d, a, a]
//获取指定元素在集合中第一次出现的索引下标
System.out.println(lista.indexOf("a")); //6
//获取指定元素在集合中最后一次出现的索引下标
System.out.println(lista.lastIndexOf("a")); //7
//根据指定下标移除元素
lista.remove(2);
System.out.println(lista); //[b, f, 456, c, d, a, a]
// 根据指定的索引下标修改元素
lista.set(1,"ff");
System.out.println(lista); //[b, ff, 456, c, d, a, a]
//根据索引下标的起始位置截取一段元素形成一个新的集合,
//截取的时候,包含开始的索引,不包含结束的索引
List<String> sublist = lista.subList(2,4);
System.out.println(sublist); //[456, c]
}
}
arraylist与vector(两种方法差不多)
arraylist和vector是list接口的两个典型实现,区别:
- vector是一个古老的集合,通常建议使用arraylist;
- ArrayList是线程不安全的,而vector是线Te程安全的;
- 即使为保证List集合线程安全,也不推荐使用Vector。
Map集合
- map用于保存具有映射关系的数据,因此map集合里保存着两组值,一组值用于保存map里的key;
另外一组用于保存map里的value。
- map中的key和value都可以是任何引用类型的数据。
- map中的key不允许重复,即同一个map对象的任何两个key通过equals方法比较返回False.
- 类似python中的dict()
Map接口与HashMap类
HashMap是对Map(接口)的一个经典实现类
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TestMap {
public static void main(String[] args) {
Map<String,Integer> map1 = new HashMap<String,Integer>();
map1.put("b",1); //添加数据
map1.put("a",2);
map1.put("e",2);
System.out.println(map1); //{a=2, b=1, e=2}
//根据key取值
System.out.println(map1.get("b")); //1
//根据key移除键值对
map1.remove("e");
System.out.println(map1); // {a=2, b=1}
//map集合的长度
System.out.println(map1.size()); //2
//判断当前的map集合是否包含指定的key
System.out.println(map1.containsKey("a")); //true
//判断当前的map集合是否包含指定的value
System.out.println(map1.containsValue(2)); //true
// map1.clear(); //清空集合
//获取map集合的key集合
Set<String> keys = map1.keySet();
System.out.println(keys);//[a, b]
//获取集合的所有value值
System.out.println(map1.values()); //[2, 1]
//遍历map集合,by map.keySet();
for (String key:keys
) {
System.out.println("key:" + key + ", value: " + map1.get(key));
}
//key:a, value: 2
//key:b, value: 1
//通过map.entrySet();
Set<Map.Entry<String, Integer>> entrys = map1.entrySet();
for (Map.Entry<String, Integer> en : entrys
) {
System.out.println("key:" + en.getKey() + ", value: " + en.getValue());
}
//key:a, value: 2
//key:b, value: 1
System.out.println("--------------------------------------");
///排序
/// TreeMap,按照key排序
Map<Integer, String> map2 = new TreeMap<Integer, String>();
map2.put(4,"a");
map2.put(5,"a");
map2.put(3,"a");
map2.put(1,"a");
System.out.println(map2); //{1=a, 3=a, 4=a, 5=a}
//TreeMap的自然排序是字典排序
Map<String,String> map3 = new TreeMap<String,String>();
map3.put("b","b");
map3.put("c","c");
map3.put("d","d");
map3.put("a","a");
map3.put("ab","ab");
System.out.println(map3); //{a=a, ab=ab, b=b, c=c, d=d}
}
}
HashMap&Hashtable
- 一般使用map集合,不会使用过于复杂对象做key。
工具类Collections
操作集合的工具类
举例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestCollections {
public static void main(String[] args) {
List<String> lista = new ArrayList<String>();
lista.add("b");
lista.add("cd");
lista.add("ca");
lista.add("a");
lista.add("1");
System.out.println(lista); //[b, cd, ca, a, 1]
Collections.reverse(lista);
System.out.println(lista); //[1, a, ca, cd, b]
//对list集合元素进行随机排序
Collections.shuffle(lista);
System.out.println(lista); //[a, 1, cd, b, ca]
// list集合字典升序
Collections.sort(lista);
System.out.println(lista); //[1, a, b, ca, cd]
//swap交换元素
Collections.swap(lista,0,4);
System.out.println(lista); //[cd, a, b, ca, 1]
System.out.println("----------查找、替换----------------");
System.out.println(Collections.max(lista)); //cd
System.out.println(Collections.min(lista)); //1
//返回指定集合中指定元素的出现次数
System.out.println(Collections.frequency(lista, "a")); // 1
//使用新值替换List对象的所有旧值
Collections.replaceAll(lista,"a","aa");
System.out.println(lista); //[cd, aa, b, ca, 1]
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Student implements Comparator<Student> {
int age;
String name;
public Student(){
}
public Student(int age, String name){
this.age = age;
this.name = name;
}
@Override
//根据年龄升序排序对象
public int compare(Student o1, Student o2) {
if (o1.age > o2.age){
return 1;
}else if (o1.age < o2.age){
return -1;
}else{
return 0;
}
}
public static void main(String[] args) {
Student s1 = new Student(12,"a");
Student s2 = new Student(12,"abbb");
Student s3 = new Student(19,"cc");
Student s4 = new Student(17,"dd");
List<Student> stus = new ArrayList<Student>();
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
for (Student stu : stus
) {
System.out.println(stu.name + "," + stu.age);
}
//a,12
//abbb,12
//cc,19
//dd,17
Collections.sort(stus, new Student());
System.out.println("________________________");
for (Student stu : stus
) {
System.out.println(stu.name + "," + stu.age);
}
//a,12
//abbb,12
//dd,17
//cc,19
System.out.println("---------------------------");
Student s = Collections.max(stus, new Student());
System.out.println(s.name + "," + s.age); //cc,19
Student ss = Collections.min(stus, new Student());
System.out.println(ss.name + "," + ss.age); //a,12
}
}
同步控制