JAVA高级(一)

一、面向对象

1、概念

在程序中使用面向对象来映射现实中的事物,使用对象关系来描述事物之间的关系,这就是面向对象思想。
     何为对象:万物皆对象  对象在程序中是new出来的   是怎么被new出来?先有类后有对象
     类和对象有什么关系?对象所属于类
类:是一类事物的统称,是一个抽象的概念
对象:对象是实例也叫实体

2、三大特性

   封装:隐藏实现细节,仅对外提供访问方式setter/getter方法  封装又称为私有的  关键字private
   继承:让某个类型的对象获得另一个类型的对象的属性和方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
   多态:对于同一个行为,不同的子类对象具有不同的表现形式。   
注意:编写类的时候可以在一个.java文件中写多个类,但是这些类只能有一个被public修饰的类,更可以分开写

3、代码演示

man类

public class Man {
    private int money;
    public void show(){
        System.out.println(money);
    }
    //主要是给属性赋值
    public void setMoney(int money){
        this.money=money;
    }
    public int getMoney(){
        return money;
    }
}

测试类:

class Person{
    String name;
    int age;
    public void eat(){
        System.out.println("吃饭");
    }
}
public class object1 {
    public static void main(String[] args) {
        //创建对象的过程
        Person p = new Person();
        p.eat();
        Man man = new Man();

        //创建对象的过程
        man.show();
        System.out.println(man.getMoney());
        man.setMoney(100);
        man.show();
        System.out.println(man.getMoney());
    }
}

二、继承

1、概念

        父类(基类/超类):被继承的类。它定义了一组属性和方法,子类将从中继承这些特性。

        子类(派生类/子类):从父类继承的类。它不仅继承了父类的属性和方法,还可以添加新的属性和方法,或者重写(覆盖)父类的方法。

2、继承的好处

        代码重用:子类可以重用父类中已经实现的代码,从而避免重复编写相同的代码。

        扩展性:子类可以扩展父类的功能,添加新的特性或方法,而无需修改父类代码。

        易维护性:当需要修改父类的功能时,子类将自动继承这些改动,减少了维护工作的复杂性。

3、继承的实现

        构造函数和析构函数:在子类构造对象时,通常会调用父类的构造函数以初始化从父类继承的属性。在对象销毁时,也会调用父类的析构函数以执行清理工作。

        方法重写(覆盖):子类可以重写父类的方法,以提供不同的实现。重写的方法通常有相同的名称和参数列表。

        方法调用:子类可以调用父类的方法,通过 super 关键字(在 Python 中)或使用父类名称(在 Java 和 C++ 中)来调用。

4、代码展示

Person

        定义了成员变量 id(整数类型)、skin(字符串类型)和 eat(字符串类型),并初始化了 id 为 10,skin 为 "yellow"eat 为 "eatting" 。定义了一个无参的 eat 方法,用于打印父类在吃饭的信息以及 id 的值。定义了一个接受整数参数 id 的构造函数,用于初始化 id 成员变量

public class Person {
    public int id =10;
    public String skin = "yellow";
    public String eat="eatting";
    public void eat(){
        System.out.println("父类在吃饭"+id);
    }

    //Person类的构造函数,接受一个整数参数id,并赋值给成员变量id
    public Person(int id){
        this.id=id;
    }

}

Man类

        继承自 Person 类。

        定义了一个 skin 方法,用于打印父类的 skin 成员变量的值。

        重写了父类的 eat 方法,在调用父类的 eat 方法后,打印 "子类在 Eatting"。

        定义了一个接受整数参数的构造函数,通过 super(id) 调用父类的构造函数来初始化父类的 id ,调用父类的 eat 方法,并将父类的 skin 成员变量修改为 "red" 。

public class Man extends Person{
    //定义skin()方法
    public void skin(){
        System.out.println(skin);
    }
/*
在面向对象编程中,重写(Override)是指子类对父类中已有的方法进行重新实现,以改变或扩展该方法的行为。
重写需要满足以下几个条件:
方法名、参数列表(包括参数的数量、类型和顺序)必须与父类中被重写的方法完全相同。
返回值类型与父类中被重写的方法相同或者是其子类(在 Java 5 及更高版本中,返回值类型可以是父类方法返回值类型的子类)。
访问修饰符不能比父类中被重写的方法更严格(例如,父类方法是 public,子类重写的方法不能是 private 或 protected)
*/

    //重写
    @Override
    public void eat(){
        //此处调用了父类中的方法eat(),在使用Man子类方法eat()时实现方法重写
        super.eat();
        System.out.println("子类在Eatting");
    }

    //Man中的一个构造函数,接收一个整数参数
    public Man(int id){
        //super调用了父类类的构造函数,给父类构造函数传参
        super(id);
        //调用的父类的eat()方法
        super.eat();
        //为父类的变量赋值
        super.skin="red";
    }
}

Woman类

        继承自 Person 类。

        重写了父类的 eat 方法,打印 "女人在" 加上父类的 eat 成员变量的值。

        定义了一个接受整数参数的构造函数,通过 super(id) 调用父类的构造函数,并调用父类的 eat 方法。

public class women extends Person{
    public void eat(){
        System.out.println("女人在"+eat);
    }
    public women(int id){
        super(id);
        super.eat();
    }
}

测试类 

        创建了一个 Man 对象 man ,并传递参数 1 给其构造函数。

        调用 man 对象的 skin 方法。

        创建了一个 women 对象 nv ,并传递参数 2 给其构造函数。

        调用 nv 对象的 eat 方法。

        调用 man 对象的 eat 方法,先执行父类的 eat 方法,再执行子类重写的 eat 方法。

public class Demon {
    public static void main(String[] args) {
        //创建Man类的对象,并传递参数1给其构造函数
        Man man = new Man(1);
        //调用Man中的skin()方法
        //父类Person传参到Man,然后调用Man里面的skin()函数
        man.skin();
        //创建women类的对象,并传递参数给其构造函数
        //父类Person传参到women,然后调用women里面的eat()函数
        women nv = new women(2);

        //调用women类中的eat()方法
        nv.eat();

        //调用Man类对象的eat()方法
        //此处用到方法重载先调用父类Preson中的eat()方法,然后调用Man()里面的eat()方法
        man.eat();
    }
}

运行结果 

5、Final关键字 

5.1. final用于变量

        当final用于变量时,它表示这个变量的值在初始化之后不能再被改变。根据变量类型的不同,final的行为有所不同:

基本数据类型(如int, double, char等):final变量的值在被初始化后无法更改。例如:

  final int MAX_VALUE = 100;
引用数据类型(如对象的引用):final变量的引用不能被重新赋值,但是引用的对象本身的状态仍然可以被修改。例如:

          final List<String> list = new ArrayList<>();
          list.add("Hello"); // 这是允许的,因为修改对象的内容
          // list = new ArrayList<>(); // 这是不允许的,因为不能改变引用的对象

5.2final用于方法

        当final用于方法时,表示这个方法不能被子类重写(override)。这是用于防止方法的行为在继承过程中被改变。例如:

public class Parent {
    public final void display() {
        System.out.println("Display method in Parent class");
    }
}

public class Child extends Parent {
    // 以下代码会导致编译错误
    // public void display() {
    //     System.out.println("Display method in Child class");
    // }
}

5.3final用于类

        当final用于类时,表示这个类不能被继承(subclass)。这是用来防止继承,从而避免子类改变其行为。例如:

public final class ImmutableClass {
    // Class implementation
}

// 以下代码会导致编译错误
// public class ExtendedClass extends ImmutableClass {
// }

5.4final用于局部变量

        在方法内部声明的局部变量使用final时,这些变量必须在声明时初始化,并且一旦赋值后,值不能再改变。例如:

public void method() {
    final int localVar = 10;
    // localVar = 20; // 这是不允许的,因为localVar是final的
}

5.5总结 

final变量:其值不可变。对于基本数据类型,值不可更改;对于引用类型,引用不可更改但对象状态可以更改。
final方法:该方法不能被子类重写。
final类:该类不能被继承。
final局部变量:在方法中声明的局部变量,必须初始化且值不可更改。

三、构造函数

构造函数与类的区别:
类(Class):
   类是一种用户自定义的数据类型,用于描述具有相同属性和行为的一组对象的模板。
类定义了对象的属性(成员变量)和方法(成员函数)。
一个类可以包含多个构造函数以及其他普通方法。
构造函数(Constructor):
1.构造函数是类中的特殊方法,用于对象的创建和初始化。
2.构造函数的名称与类名相同,没有返回值类型。
3.其主要目的是在创建对象时,为对象的成员变量赋予初始值,或者执行一些与对象初始化相关的必要操作。
4.每个类至少有一个构造函数,如果没有显式定义,Java 会提供一个默认的无参构造函数。

1、普通构造函数

实体类:

public class Person {
    static String name;
    static String sex;
    static int age;
    static int id;
    //创建无参数构造方法
    public Person(){
        System.out.println("无参数构造方法");
    }
    //普通方法
    public void method(){
        System.out.println("普通方法"+name);
    }
    //有参函数构造,初始成员变量
    public Person(String name,String sex,int age,int id){
        this.name=name;
        this.sex=sex;
        this.age=age;
        this.id=id;
    }
}

测试类:

public class buildFunction {
    public static void main(String[] args) {
        //创建对象的过程,此过程调用默认的无参构造函数
        Person p=new Person();
        p.method();
        //创建Person类的对象,调用有参的构造函数
        Person p1 = new Person("赵云", "男", 1, 1);
        p1.method();
    }
}

2、静态以及优先级

Person类

static表示静态
static修饰的变量成为静态变量修饰的方法称为静态方法
特点:
1. 静态只能访问静态不能访问非静态
2. 静态不能和this,super关键字共存
3. 静态随着类的加载而加载
4. 静态可以由类名直接访问

优先级:静态代码块>构造代码块>构造函数>普通函数
静态代码块可以做数据共享
静态代码块只被执行一次
public class Person {
    static {
        System.out.println("静态代码块");
    }
    
    {
        System.out.println("构造代码块");
    }
    public Person(){
        System.out.println("构造函数");
    }
    public static void method(){
        System.out.println("普通静态方法");
    }
}

测试类

public class functionStatic {
    public static void main(String[] args) {

        //调用被执行
        Person p1 = new Person();
        Person p2= new Person();
        Person p3 = new Person();
        p1.method();//也可以用Person.method();

    }
}

输出结果 

四、抽象类

1、概念

在 Java 中,抽象类是一种不能被实例化的类,它可以包含抽象方法和非抽象方法。
以下是关于 Java 抽象类的一些关键特点和要点:
1.抽象方法:抽象类可以包含抽象方法。抽象方法是只有方法签名(方法名、参数列表和返回类型),但没有方法体的方法。抽象方法使用 abstract 关键字修饰,例如: public abstract void myAbstractMethod(); 。
2.不能实例化:由于抽象类可能包含未完全定义的方法(即抽象方法),所以不能直接创建抽象类的对象。
3.继承和实现:子类继承抽象类后,必须实现抽象类中的所有抽象方法,否则子类也必须声明为抽象类。
4.部分实现:抽象类可以提供部分方法的实现,为子类提供一些通用的功能和行为,子类可以选择重写这些方法或者直接使用父类的实现。
5.代码复用:通过将公共的属性和方法放在抽象类中,可以实现代码的复用,减少重复代码的编写。
6.设计和架构:抽象类有助于设计良好的类层次结构,它可以定义一些通用的规则和行为,使得整个系统的架构更加清晰和易于理解。

2、代码演示

animal类

//抽象类使用关键字 abstract 修饰。可以包含抽象方法和非抽象方法(普通方法)。
public abstract class animal {
    //构造函数
    public animal(){
        System.out.println("父类(animal)的构造函数");
    }
    public abstract void method();
}

duck类

public class duck extends animal{
    public duck(){
        //调用了父类的无参构造函数
        super();
    }
    public  void method(){
        System.out.println("子类覆盖抽象方法");
    }
}

测试类

public class demon {
    //抽象类不能被实例化,只能被子类覆盖实现
    public static void main(String[] args) {

        //animal a = new animal();
        duck d =new duck();

        //抽象方法只能通过子类覆盖实现
        //animal b = new animal();
        d.method();
    }

}

五、接口 

1、概念

关键字:interface
实现一个接口关键字:implements
特点:java中类不能多继承,但能多实现,接口中的方法都是抽象方法,接口中的变量都是常量
     接口中的常量可以不用abstract方法,也可以不用写

2、代码演示

usb接口

public interface usb {
    //抽象方法,接口里面都是抽象方法
    public abstract void usbMethod();

    //常量
    public static final String STR="STR";
}

PowerSuppely接口

public interface PowreSuppply {
    public abstract void powerMethod();
}

mouse类

public class mouse implements usb,PowreSuppply{
    public void usbMethod(){
        System.out.println("鼠标已插入");
    }
    public void powerMethod(){
        System.out.println("鼠标电源已接入");
    }

}

keyboard类

public class keyBoard implements usb,PowreSuppply{
    public void usbMethod(){
        System.out.println("键盘已插入");
    }
    public void powerMethod(){
        System.out.println("键盘电源已接入");
    }
}

测试类

public class demon {
    public static void main(String[] args) {
        keyBoard jianpan = new keyBoard();
        jianpan.usbMethod();
        mouse shubiao = new mouse();
        shubiao.usbMethod();
        jianpan.powerMethod();
        shubiao.powerMethod();
        System.out.println(usb.STR);
    }
}

测试结果 

3、多态性展示 

Aniaml接口

public interface Animal {
    public  void runMethod();
}

Fish类

public class Fish implements Animal{
    public void runMethod(){
        System.out.println("鱼飞");
    }
}

Dog类

public class Dog implements Animal{
    public void runMethod(){
        System.out.println("狗飞");
    }
}

Bird类

public class Bird implements Animal{
    public void runMethod(){
        System.out.println("鸟飞");
    }
}

测试类

public class Demon {
    public static void main(String[] args) {
        //父类引用指向子类对象
        Animal dog = new Dog();
        dog.runMethod();
        Animal bird = new Bird();
        bird.runMethod();
        Animal fish = new Fish();
        fish.runMethod();
        Dog d = new Dog();
        d.runMethod();
    }
}

测试结果

六、内存地址和常量池 

public class place1 {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        
        //这里,s1 和 s2 都是通过 new 关键字创建的 String 对象,它们在堆内存中占据不同的位置。虽然它们的内容相同,但 == 比较的是它们的内存地址,因此 s1 == s2 结果为 false。
        System.out.println(s1 == s2);//false
        
        // .equals 方法比较的是内容,所以 s1.equals(s2) 结果为 true。
        System.out.println(s1.equals(s2));//true

       String s3="hello";
        String s4="hello";
        //字符串字面量(如 "hello")会被存储在常量池中。如果一个字符串已经在常量池中,后续创建相同内容的字符串字面量会引用池中的同一个对象。因此 s3 和 s4 都引用了常量池中的同一个 "hello" 字符串对象,所以 s3 == s4 结果为 true。
        System.out.println(s3 == s4);//true

        String s5 = new String("hello");
        String s6 = "hello";
        //s5 是通过 new 关键字创建的新 String 对象,它位于堆内存中,而 s6 是指向常量池中 "hello" 字符串的引用。因此,s5 和 s6 不指向同一个内存位置,所以 s5 == s6 结果为 false。
        System.out.println(s5 == s6);//false
    }
}

七、异常

        在 Java 中,异常是在程序运行时发生的不正常情况。异常处理是一种机制,用于处理程序运行过程中可能出现的错误或异常情况,以增强程序的健壮性和容错性。

Java 中的异常可以分为两类:

        检查型异常(Checked Exception):这些异常在编译时会被检查,如果方法可能抛出检查型异常,那么调用该方法的代码必须处理这个异常,要么使用 try-catch 语句捕获并处理,要么在方法声明中使用 throws 关键字声明将异常抛出给上层调用者处理。例如,IOExceptionSQLException 等。

        非检查型异常(Unchecked Exception):也称为运行时异常(Runtime Exception),在编译时不会被强制要求处理。这些异常通常是由于编程错误导致的,例如,NullPointerExceptionArrayIndexOutOfBoundsExceptionArithmeticException 等。

1、异常代码

此处除数为0,产生异常,虽然主函数main()也抛出了异常不处理,但运行时还是会报错

public class Demon1 {
    public static void main(String[] args) throws Exception {
        method();
    }

    public static void method() throws Exception{
        int i = 1/0;
        System.out.println(i);
    }
}

 2、try-catch解决异常

public class Demon2 {
    public static void main(String[] args) {
        method();
    }

    private static void method() {
        try{
            int i=1/0;
            System.out.println(i);
        }catch(Exception e){
            //e.printStackTrace();//打印异常信息
            System.out.println((1 / 1));
        }
    }
}

3、制造异常 

public class Demon3 {
    public static void main(String[] args) {
        int result = 0;
        try {
            result = method(1,-1);
        } catch (ExceptionClass e) {
            throw new RuntimeException(e);
        }
        System.out.println(result);
    }
    public static int method(int x,int y) throws ExceptionClass {

        // 自定义异常也叫做自己制造异常
        if(y < 0){
            // 使用throw关键字制造异常
            throw new ExceptionClass("除数是负数了!");
        }
        int result = x/y;
        return result;
    }
}

八、API

1、StringBuffer

        StringBuffer类: String和StringBuffer的区别:由于字符串是常量,因此一旦创建,其内容和长度是不可改变的。如果要对一个字符串进行修改,只能新建字符串,所以JDK中提供了一个StringBuffer类(也称为字符串缓冲区)

public class stringbufer {
    public static void main(String[] args) {
        System.out.println("1.add");
        add();
        System.out.println("2.delete");
        delete();
        System.out.println("3.update");
        update();
    }

    private static void add() {
        StringBuffer sb = new StringBuffer();
        //追加内容
        sb.append("sb");
        System.out.println("append追加结果为:"+sb);
        sb.insert(0,"张三");
        System.out.println("append追加结果为:"+sb);

    }
    
    private static void delete() {
        StringBuffer sb = new StringBuffer("12345");
        //删除[1,3)的索引位置
        sb.delete(1,3);
        System.out.println("DeleteResult:"+sb);
        //指定位置删除
        sb.deleteCharAt(0);
        System.out.println("DeleteResult:"+sb);
    }
    
    private static void update() {
        StringBuffer sb = new StringBuffer("abcdefg");
        //指定位置修改
        sb.setCharAt(1,'B');
        System.out.println("DeleteResult:"+sb);
        //替换
        sb.replace(0,2,"AB");
        System.out.println("替换后的内容为:"+sb);
        //字符串反转
        System.out.println(sb.reverse());
    }
}

2、字符串查重

        编写程序,查看"abc"在字符串中出现的次数

public class OutRepeat {
    public static void main(String[] args) {
        String str="abcabcabckjhfoklewdhfoabc";
        String key = "abc";
        System.out.println(getCount(str, key));
    }

    /*
    substring(int beginIndex, int endIndex) :
    返回一个新的字符串,它是原始字符串从beginIndex(包括)开始到endIndex(不包括)的部分
     */

    private static int getCount(String str, String key) {
        int count = 0;
        int index = str.indexOf(key);//字符串在str中首次出现的位置
        while(index!=-1){
            count++;
            str = str.substring(index+key.length());//截取剩余字符串,然后继续查找
            index = str.indexOf(key);//再次查找
        }
        return count;
    }
}

3、System类

        查看一段代码运行的时间

public class SystemObject {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        int num = 0;
        for(int i = 0 ; i < 100000 ; i ++){
            num+=i;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("程序运行的时间为"+(endTime-startTime));
    }
}

 4、数组复制

public class CopyArray {
    public static void main(String[] args) {
        int arr1[] = {1,2,3,4,5,6,7,8};
        int arr2[] = {11,12,13,14,15,16,17,18,19};
        //数组arr1从下标为2的位置拿取元素,从arr2下标为3的位置开始复制,步长为4
        System.arraycopy(arr1,2,arr2,3,4);
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(i+ "\t"+ arr2[i]);
        }

    }
}

 

 5、包装类

public class PackageClass {
    public static void main(String[] args) {

        //字符串转化为int
        String str = "6";
        /*
        Integer.parseInt(str) 是 Java 中的一个方法,用于将一个表示整数的字符串 str 转换为对应的 int 类型的整数。
        如果字符串 str 不能被正确解析为整数(例如,字符串不包含有效的整数字符,或者格式不正确),将会抛出 NumberFormatException 异常。
         */
        int num = Integer.parseInt(str);
        System.out.println(num==6);


        //int类型转化为字符串
        int num2 = 10;
        Integer integer1 = new Integer(num2);// 创建一个 Integer 对象 integer1,并通过构造函数将 num2 的值传递进去进行初始化
        System.out.println(integer1.toString()+1); // 调用 integer1 的 toString 方法将其转换为字符串,然后与数字 1 进行字符串拼接并输出


        int num3 = 30;
        Integer integer2 = new Integer(20);
        int sum = integer2.intValue()+num3;//将 Integer 对象转换为基本数据类型 int
        System.out.println(sum);

    }
}

九、集合 

集合按照其存储结构分为两大类:单列集合 双列集合

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List和Set 其中

List的特点:元素有序,可重复。

Set的特点是元素无序,不可重复

List接口的主要实现类,ArrayList和LinkedList Set接口的主要实现类由HashSet和TreeSet Map:双列集合的根接口,用于存储具有键(key)、值(value)映射关系的元素,每个元素都包含一对键值,在使用Map集合时可以通过指定的key找到对应的Value

1、ArryList 

Java 集合框架提供了一组用于存储和操作一组对象的数据结构。主要的集合接口包括 Collection 和 Map
ArrayList内部封装了一个长度可变的数组对象,当存入元素超过数组长度时,ArrayList会在内存中分配一个跟大的数组来存储这些元素。所以可以将ArrayList集合类当作可变数组来看;
优点:
    数组结构允许程序通过索引的方式来访问元素,因此使用ArryList集合查找元素很便捷
缺点:
    由于ArrayList集合的底层是使用一个数组来保存元素,在增加或者删除指定位置的元素会导致创建新的数组
效率比较低,因此不适合做大量的增删改查操作;
public class SignalGather {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        list.add("你好");
        list.add("我好");
        list.add("大家好");
        System.out.println("List Length:" + list.size());
        System.out.println("Value Index 2:" + list.get(2));
        /*Iterator(迭代器)是一个用于遍历集合元素的接口。
           它提供了一种统一的方式来遍历不同类型的集合,而无需关心集合的具体实现细节。
         */

        //迭代遍历
        Iterator iterator = list.iterator();//获取了一个列表list的迭代器iterator
        while (iterator.hasNext()) {//检查迭代器中是否还有下一个元素
            Object obj = iterator.next();//iterator.next() 方法返回迭代器中的下一个元素,并将其赋值给 obj 变量
            System.out.println(obj);
        }
        //增强for循环
        for (Object o : list) {
            System.out.println(o);
        }

        //字母排序
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Taobao");
        sites.add("Wiki");
        sites.add("Runoob");
        sites.add("Weibo");
        sites.add("Google");
        Collections.sort(sites);  // 字母排序
        for (String i : sites) {
            System.out.println(i);
        }
    }
}

2、LinkedList

public class Link {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("Link1");
        list.add("Link2");
        list.add("Link3");
        list.add("Link4");
        list.add("Link5");

        System.out.println(list);
        //第一个位置添加数据
        list.addFirst("司马懿");

        //第三个位置添加数据
        list.add(3,"link3");
        System.out.println(list);

        //获取第一个位置上的数据
        System.out.println(list.getFirst());

        //删除第三个位置的数据
        list.remove(3);
        System.out.println(list);

        //删除第一个位置的数据
        list.removeFirst();
        System.out.println(list);

    }
}

3、Set

Set接口和List接口一样,都继承自Collection接口 特点:无序,不可重复 HashSet集合 HashSet是Set集合的实现类,它所存储的数据是不可重复的,元素都是无序的 判断是否重复的底层原理:当向HashSet集合中添加一个对象时,首先会调用该对象的hashCode()方法来计算对象的哈希值,从而确定元素的位置如果此时哈希值相同,在调用对象的equals()方法来确保该位置没有重复元素。

Student类 

public class student {
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    private int id;
    private String name;
    public student(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public student(){
    }
}

 测试类

public class Demon {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        student s1 = new student(1, "张三");
        student s2 = new student(2, "李四");
        student s3 = new student(3, "王五");
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        System.out.println(hashSet);
    }
}

4、Map接口

        Map接口: Map接口是一个双列集合,它的每一个元素都包含一个键对象key和值对象value,键和值对象之间存在一种对应关系, 称为映射 从Map集合种访问元素时,只要指定了key,就能找到对应的value。

        Map接口还有一个实现类Hashtable,它和HashMap的区别在于它是线程安全的

import java.util.*;

public class MapClass {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("1","关羽");
        map.put("2","张飞");
        map.put("3","赵云");
        map.put("2","张飞");
        map.put("4","马超");
        map.put("5","黄忠");
        map.put(6,"魏延");
        map.put(7,"周仓");
        System.out.println(map.get("2"));
        System.out.println(map.get(6));

        System.out.println("第一种遍历方式:");
        Set set = map.keySet();//获取map中的所有键值对,存储在一个Set中
        Iterator iterator = set.iterator();//获取Set的迭代器
        while(iterator.hasNext()){
            Object obj = iterator.next();//获取键
            Object value = map.get(obj);//获取键值
            System.out.println(obj + ":" + value);
        }

        System.out.println("第二种遍历方式:");
        Set sett = map.entrySet();
        Iterator iterator1 = sett.iterator();
        while(iterator1.hasNext()){
            Map.Entry entry = (Map.Entry) iterator1.next();//获取下个键值对
            Object key = entry.getKey();
            Object value = entry.getValue();
            System.out.println(key + ":" + value);
        }

        System.out.println("第三种遍历方式:");
        Collection values = map.values();//获取map中的所有值,存储在Collection中
        Iterator iterator3 = values.iterator();
        while(iterator3.hasNext()){
            Object obj = iterator3.next();
            System.out.println(obj);
        }

    }
}

 5、泛型

        Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

        泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

java 中泛型标记符:

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(Java 类)
  • K - Key(键)
  • V - Value(值)
  • N - Number(数值类型)
  •  - 表示不确定的 java 类型

1.打印不同数组元素

public class GenericMethodTest
{
   // 泛型方法 printArray                         
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素            
         for ( E element : inputArray ){        
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }
 
    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
 
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组
 
        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    } 
}

2. 得到不同类型的最大值

public class MaximumTest
{
   // 比较三个值并返回最大值
   public static <T extends Comparable<T>> T maximum(T x, T y, T z)
   {                     
      T max = x; // 假设x是初始最大值
      if ( y.compareTo( max ) > 0 ){
         max = y; //y 更大
      }
      if ( z.compareTo( max ) > 0 ){
         max = z; // 现在 z 更大           
      }
      return max; // 返回最大对象
   }
   public static void main( String args[] )
   {
      System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
                   3, 4, 5, maximum( 3, 4, 5 ) );
 
      System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
                   6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
 
      System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
         "apple", "orange", maximum( "pear", "apple", "orange" ) );
   }
}

3.类型通配符

import java.util.*;
 
public class GenericTest {
     
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();
        
        name.add("icon");
        age.add(18);
        number.add(314);
 
        getData(name);
        getData(age);
        getData(number);
       
   }
 
   public static void getData(List<?> data) {
      System.out.println("data :" + data.get(0));
   }
}

十、线程基础 

         Java 的线程是实现并发编程的核心工具,允许同时执行多个任务。线程在 Java 中的引入主要是为了提高程序的效率和响应性。以下是关于 Java 线程的详细介绍:

1、 线程的基本概念

        线程(Thread):线程是程序中独立执行的最小单位,每个线程都有自己的程序计数器、栈和局部变量。多个线程共享进程的资源(如内存)。
        进程(Process):进程是系统进行资源分配和调度的基本单位,是线程的集合。一个进程可以包含多个线程。

2.、创建线程的方法

        Java 提供了两种主要的方式来创建线程:


2.1 继承 Thread 类

MyThread类

public class MyThread extends Thread{
    public void run(){
        while (true){
            System.out.println("myThread已启动");
        }
    }
    }

测试类

public class Demon {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        run();
    }
    private static void run(){
        while (true){
            System.out.println("主函数已启动");
        }
    }
}

2.2 实现 Runnable 接口

MyThread2类

public class MyThread2 implements Runnable{
    public void run(){
        while(true){
            System.out.println("MyThread2正在运行");
        }
    }
}

测试类

public class Demon2 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread thread = new Thread( myThread2);
        thread.start();
        while (true){
            System.out.println("Main2正在运行");
        }
    }
}

3、 线程的生命周期

新建(New):线程对象被创建,但尚未调用 start() 方法。
可运行(Runnable):线程已经调用了 start() 方法,但尚未获得 CPU 时间片。
运行(Running):线程获得了 CPU 时间片并在执行 run() 方法。
阻塞(Blocked):线程因等待资源或锁而被阻塞。
等待(Waiting):线程因调用 wait() 方法而进入等待状态,直到其他线程调用 notify() 或 notifyAll()。
超时等待(Timed Waiting):线程在指定时间内等待,如调用 sleep() 或 join() 方法。
终止(Terminated):线程执行完毕或者因异常退出。

4、线程的控制方法

start():启动线程,调用 run() 方法。
run():线程的主方法,包含线程要执行的代码。
sleep(long millis):使当前线程暂停执行指定的时间。
join():等待线程终止。
yield():使当前线程让出 CPU 资源。
interrupt():中断线程的休眠、等待或阻塞状态。
isAlive():检查线程是否还在运行。

5、线程优先级

        在此代码中,虽然设置了最高和最低的优先级,但是是否运行得看概率,概率大的优先级高,但不一定先运行

class Task implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(500);
            }catch (InterruptedException e){
                e.printStackTrace();
            }if(i>0){
                System.out.println(Thread.currentThread().getName() + i);
            }

        }
    }
}
public class Priority {
    public static void main(String[] args) {
        Task t1 = new Task();
        Task t2 = new Task();
        Thread p1 = new Thread(t1,"最高优先级");
        Thread p2 = new Thread(t2,"最低优先级");
        p1.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
        p2.setPriority(Thread.NORM_PRIORITY); // 设置普通优先级
        p1.start();
        p2.start();
    }
}

6、线程让步

线程让步可以通过 yield ()方法来实现,该方法和 sleep ()方法有点相似,都
可以让当前正在运行的线程暂停,区别在于 yield() 方法不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次。
当某个线程调用 yield ()方法之后,只有与当前线程优先级相同或者更高的线程才能获得执行的机会。
class YieldThread extends Thread{
    public YieldThread(String name){
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 6; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
            if(i==3){
                //Thread.yield();
                System.out.println("线程让步");
                Thread.yield();
            }
        }
    }
}
public class Demon {
    public static void main(String[] args) {
        Thread t1= new YieldThread("线程A");
        Thread t2 = new YieldThread("线程B");
        t1.start();
        t2.start();
    }
}

 

 7、线程插队

class EcyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 8; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try{
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
public class CutThread {
    public static void main(String[] args) throws InterruptedException{
        EcyThread ecyThread = new EcyThread();
        Thread thread1 = new Thread(ecyThread,"线程1");
        thread1.start();
        for (int i = 0; i < 8; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            if(i==4){
                System.out.println("线程插队");
                thread1.join();
            }
            Thread.sleep(1000);
        }
    }
}

8、Sleep

class Task2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                System.out.println(Thread.currentThread().getName()+i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}
public class sleep {
    public static void main(String[] args) {
        Task2 task2 = new Task2();
        Thread thread = new Thread(task2,"线程");
        thread.start();
    }
}

9、售票案例 

        现有10张票,现在通过4个窗口进行售卖。

        第一种方式,直接继承Thread的四个窗口进行票的减减售卖,此时发现每个窗口都卖了10张票,所以代码存在问题

class TickThread extends Thread{
    public void run(){
        int count = 0;
        int i = 10;
        while(true){
            if(i>0){
                Thread th = Thread.currentThread();
                String name = th.getName();
                System.out.println(name+"正在售出第" + (i--) + "张票\t\t"+count++);
            }
        }
    }
}
public class Demon3 {
    public static void main(String[] args) {
        TickThread tickThread = new TickThread();
        new Thread(tickThread,"窗口1").start();
        new Thread(tickThread,"窗口2").start();
        new Thread(tickThread,"窗口3").start();
        new Thread(tickThread,"窗口4").start();
    }
}

        第二种方式,继承Runnable的多线程来售票 ,现在发现售票正常

class TickThread2 implements Runnable{
    private int i=10;
    public void run() {
        while (true){
            if(i>0){
                Thread th = Thread.currentThread();
                String name = th.getName();
                System.out.println(name+"正在发售第" +(i--) + "张票");
            }
        }
    }
}

public class Demno4 {
    public static void main(String[] args) {
    TickThread2 tickThread2 = new TickThread2();
    new Thread(tickThread2,"窗口1").start();
    new Thread(tickThread2,"窗口2").start();
    new Thread(tickThread2,"窗口3").start();
    new Thread(tickThread2,"窗口4").start();
    }
}

 

        第三种方式来改进一下,使用 synchronized 关键字对 obj 对象进行加锁,然后抛出异常来每隔半秒售票,查看售票结果正常

class TicketThread implements Runnable{
    private int i = 10;
    Object obj = new Object();

    @Override
    public void run() {
        while (i>0){
            synchronized (obj){
                //使用 synchronized 关键字对 obj 对象进行加锁,这意味着同一时刻只有一个线程能够进入这个同步块执行代码。
            try{
                Thread.sleep(500);
            }catch (InterruptedException e){
               throw new RuntimeException(e);
            }
            if(i>0){
                System.out.println(Thread.currentThread().getName() + "卖出的票" + i--);
            }
        }
    }
}
}
public class Ticket {
    public static void main(String[] args) {
        TicketThread ticketThread = new TicketThread();
        new Thread(ticketThread,"窗口1").start();
        new Thread(ticketThread,"窗口2").start();
        new Thread(ticketThread,"窗口3").start();
        new Thread(ticketThread,"窗口4").start();
    }
}

         第四种方式来进行售票,创建一个synchronized修饰的售票函数,然后售完退出,结果正常

import java.util.concurrent.atomic.AtomicInteger;

class TickThread2 implements Runnable{
 private AtomicInteger i = new AtomicInteger(10);

    @Override
    public void run() {
        while(i.get()>0){
            method();
        }
    }

    private synchronized void method() {
        try{
            Thread.sleep(500);
        }catch(InterruptedException e){
            e.printStackTrace();
        }if (i.get()>0){
            System.out.println(Thread.currentThread().getName() + "卖出的票" + i.decrementAndGet());
        }
        else {
            System.exit(0);
        }
    }
}
public class Ticket2 {
    public static void main(String[] args) {
        TickThread2 tickThread2 = new TickThread2();
        new Thread(tickThread2,"窗口1").start();
        new Thread(tickThread2,"窗口2").start();
        new Thread(tickThread2,"窗口3").start();
        new Thread(tickThread2,"窗口4").start();

    }
}

十一、字节流 

1、InputStream

public class InputStream {
    public static void main(String[] args) throws Exception {
        FileInputStream fileInputStream = new FileInputStream("C:/Users/20665/OneDrive/桌面/1.txt");
        int b=0;
        while(true){
            b=fileInputStream.read();
            if(b==-1){
                break;
            }
            System.out.println(b);
        }
        fileInputStream.close();
    }
}

2、OutputStream 

public class OutputStreamm {
        public static void main(String[] args) throws Exception{
            OutputStream outputStream = new FileOutputStream("C:/Users/20665/OneDrive/桌面/1.txt");
            String str = "张三";
            byte[] bytes = str.getBytes();
            for (int i = 0; i < bytes.length; i++) {
                outputStream.write(bytes[i]);
            }
            outputStream.close();
        }
    }

 

 3、Copy

把桌面上的1.txt文件内容复制到新建的一个2.txt文件中

package com.jn.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

public class copy {
    //throws Exception 表示该方法可能抛出异常,需要在调用处进行处理或继续抛出
    public static void main(String[] args) throws Exception{
        //创建了一个文件输入流,用于读取指定路径的文件
        InputStream is = new FileInputStream("C:/Users/20665/OneDrive/桌面/1.txt");
        // 创建了一个文件输出流,用于将数据写入指定路径的文件
        OutputStream os = new FileOutputStream("C:/Users/20665/OneDrive/桌面/2.txt");
        int len;
        long beginfTime = System.currentTimeMillis();
        //循环读取文件的内容,并将读取到的字节写入到输出文件
        while ((len = is.read())!=-1){//当 read() 方法读取到文件末尾时,会返回 -1
            os.write(len);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cope time:"+(endTime - beginfTime));
        is.close();
        os.close();
    }
}

 

4、Buffer 缓冲区

把复制文件存入到缓冲区来减少系统操作时间

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class Buffer {
    //抛出异常
    public static void main(String[] args) throws Exception{
        //创建输入流
        InputStream is = new FileInputStream("C:/Users/20665/OneDrive/桌面/java/io/1.txt");
        //输出流
        OutputStream os = new FileOutputStream("C:/Users/20665/OneDrive/桌面/java/io/buffer/2.txt");

        //创建一个大小为 1024 字节的缓冲区,用于在读取和写入文件时提高效率。
        byte[] buffer = new byte[1024];
        int len;
        long beginTime = System.currentTimeMillis();
        //从输入流中读取数据到缓冲区,并获取读取的字节数。 将缓冲区中有效数据(从索引 0 开始,长度为 len )写入输出流
        while((len = is.read(buffer))!=-1) os.write(buffer, 0, len);
        long endTime = System.currentTimeMillis();
        System.out.println("拷贝时间为:" + (endTime - beginTime));
        is.close();
        os.close();
    }
}

5、Buffer缓冲流 

 之间创建一个带缓冲区的输入输出流来节省系统响应时间

public class BufferFlow {
    public static void main(String[] args) throws Exception{
        //创建一个带缓冲区的输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/20665/OneDrive/桌面/java/io/1.txt"));
        //输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/20665/OneDrive/桌面/java/io/buffer/2.txt"));
        int len;
        while((len = bis.read())!= -1){
            bos.write(len);
        }
        bis.close();
        bos.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值