Java core 基础概念

JAVA学习中记录的一些笔记,不断更新

目录

1.标识符

2.变量

3.逻辑运算符

4.位运算符(高效运算)

5.语句

6.函数(方法)

7.内存结构

8.数组

9.面向对象

10.匿名对象

11.访问控制修饰符

12.构造函数

13.this关键字

14.static关键字

15.对象的初始化过程

16.继承

17.super关键字

18.final关键字

19.abstract关键字

20.接口

21.多态

22.内部类

 

23.匿名内部类

24.异常

25.包

26.多线程

27.String

28.包装类

29.集合

30.List集合

31.Set集合

32.集合泛型

33.Map

 

34.Collections

35.Arrays

37.增强for循环

38.可变参数

39.静态导入

40.System

41.Runtime

42.Date

43.Calendar

 

44.Math Random

45.IO流

46.异常的日志信息


1.标识符

包名:xxxyyyzzz

类名接口名:XxxYyyZzz

变量名函数名:xxxYyyZzz

常量名:XXX_YYY_ZZZ

 

2.变量

基本数据类型:数据型,字符型,布尔型(栈内存)

引用数据类型:类,接口,数组(栈内存引用堆内存)

当数据不确定时,且需要对数据进行存储时,定义变量

 

3.逻辑运算符

&和&&:

&:无论左边是true还是false,右边都运算

&&:当左边为false时,右边不运算

|和||

|:两边都参与运算

||:当左边为true时,右边不运算

 

4.位运算符(高效运算)

左移<<:乘2的移动位数次幂

右移>>:除2的移动位数次幂

>>:最高位补什么由原有数据的最高位值而定

        如果最高位0,右移后,用0补空位

        如果最高位1,右移后,用1补空位

>>>:无论最高位是什么,右移后,都用0补

异或^:A^B^B=A(加密解密,数据交换)

 

5.语句

switch:判断的具体数值不多,且符合byte,short,int,char,String(1.7)类型

if:对区间判断,对结果为Boolean类型判断

for:变量有作用域,循环增量定义在for中,且只在for中有效,for执行完毕后,该增量在内存中消失。for(;;){}-->(无限循环)

while,dowhile:运算结果用于循环外,while(true){}-->(无限循环)

break:跳出,应用于选择结构和循环结构

continue:继续,应用于循环结构,结束本次循环继续下次循环

 

6.函数(方法)

重载(overload):同一个类中,同名且参数个数或参数类型不同,与返回值类型无关。当定义的功能相同,但参与运算的位置内容不同,定义一个函数名称以表示该功能,通过参数列表的不同来区分多个同名函数。

主函数(main 不是关键字):是一个特殊的函数,作为程序入口,可以被JVM调用

public static void main(String[] args)args==arguments(n.参数)

public:代表该函数访问权限最大

static:代表主函数随着类的加载就已经存在了

void:主函数没有具体的返回值

String [] args:函数的参数,参数类型是一个字符串数组,传入的是new String[0] 空数组

                        javac mainDemo

                        java mainDemo haha hehe heihei

                        System.out.println(args[0]);--->haha

 

7.内存结构

栈内存:用于存储局部变量,当数据使用后,所占空间会自动释放

堆内存:数组和对象,通过new建立的实例都存放在堆内存中,每一个实体都有内存地址值,实体中的变量都有默认初始化值,实体不在被使用,会在不确定的时间内被垃圾回收器回收。

               [I@xxxxxx:一维数组,integer类型元素,内存地址(哈希值,十六进制)

方法区:

本地方法区:

寄存器:

 

8.数组

排序:Arrays.sort(arr);

选择排序:内循环结束一次,最值出现在头角标位上

public static void selectSort(int []arr)
{
    for(int x=0;x<arr.length;x++)
    {
       for(int y=x+1;y<arr.length;y++)
       {
           if(arr[x]>arr[y])
           {
               int temp=arr[x];
               arr[x]=arr[y];
               arr[y]=temp;                
           }
       }
    }
}

冒泡排序:

public static void bubbleSort(int []arr)
{
    for(int x=0;x<arr.length-1;x++)
    {
       for(int y=0;y<arr.length-x-1;y++)//-x:让每一次比较的元素减少  -1:避免角标越界
       {
           if(arr[y]>arr[y+1])
           {
               int temp=arr[y];
               arr[y]=arr[y+1];
               arr[y+1]=temp;                
           }
       }
    }
 }

 

9.面向对象

封装,继承,多态

具体对象就是java在堆内存用new建立实体

属性就是类中变量,行为就是类中函数(成员变量和成员方法)

类类型变量指向堆内存中的对象

成员变量和局部变量 作用范围

成员变量作用于整个类中,存放于堆内存,因为对象的存在,才在内存中存在

局部变量作用于函数中,或者语句中,存放于栈内存中

 

10.匿名对象

当对对象的方法(非属性变量,调用完即在内存中成为垃圾,等待回收)只调用一次时,可简化为匿名对象

可以将匿名对象作为实际参数进行传递

Car c=new Car();
show(c);

show(new Car());

 

11.访问控制修饰符

用于控制被修饰变量、方法、类的可见范围.
public 的访问级别是最高的,其次是 protected、默认和 private.
成员变量和成员方法可以处于4个访问级别中的一个:公开、受保护、默认或私有.
存在继承关系时,父类不可以是 private,因为子类无法继承
顶层类可以处于公开或默认级别,顶层类不能被 protected 和 private 修饰. (外部类)
局部变量不能被访问控制修饰符修饰

 

private:私有,用于修饰类中成员(成员变量和成员方法),私有只在本类中有效,对象不能直接访问,提供get,set方法进行访问。仅仅是封装的一种表现形式

默认权限(不写default):介于私有和共有之间

public:

protected:

图转自 https://blog.csdn.net/Xk632172748/article/details/51755438

12.构造函数

默认构造函数(系统自带): 类名(){}  默认构造函数的权限随着类的变化而变化

自定义构造函数后,默认构造函数消失

对象一建立,就会调用与之对应的构造函数,可以用于给对象进行初始化,只运行一次

构造代码块 {}

作用:给对象进行初始化 对象一建立就运行,而且优先于构造函数执行

构造代码块是给所有对象进行统一初始化(定义不同对象共性的初始化内容)

构造函数是给对应的对象初始化

 

13.this关键字

代表对本类对象的引用

默认被省略

用于区分局部变量和成员变量同名的情况

代表它所在函数所属对象的引用

当定义类中功能(方法)时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象

但凡本类功能内部使用了本类对象,都用this表示

this语句:只能用于在构造函数间进行互相调用,this语句只能定义在构造函数第一行,因为初始化要先执行

Person()
{
    this.name="xixi";
}
Person(String name)
{
    this();
    this.name=name;
}
Person(String name,int age)
{
    this(name);
    //this.name=name;
    this.age=age;
}

 

14.static关键字

静态 用于修饰成员(成员变量,成员函数),成员被静态修饰后,成员不存在于堆内存中,而存在于方法区(共享区,数据区),在内存中只有一个副本

被修饰的成员:随着类的加载而加载,优先于对象存在,被所有对象所共享,共享数据 (country=“CN”(类变量))

                        可以直接被类名调用(类名.静态成员),因为静态成员存在时,对象可能不存在。

注意事项:静态方法只能访问静态成员,非静态方法既可以访问静态也可以访问非静态,

                 静态方法中不可以写this,super关键字,主函数是静态的

利处:对对象的共享数据进行单独空间存储,节省空间,没有必要每个对象都存储一份。

弊处:生命周期过长,访问出现局限性

用处:当对象中出现共享数据(值)时,该数据被静态修饰,对象特有数据定义成非静态。

           当功能内部没有访问到非静态数据时,该功能可以定义成静态方法

应用:每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。

           工具类(ArrayTool等)不需要对象,可将类中方法定义成静态的,直接通过类名调用。因为不需要建立对象,可将构造函数私有化强制不能建立对象。

静态代码块: static{ 语句 }  随着类的加载而执行,只执行一次。用于给类进行初始化。

 

15.对象的初始化过程

class Person
{
    private String name="xixi";
    private int age;
    private static String country="CN";
    Person (String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    {
        System.out.println(name+"--"+age);
    }
    public void setName(String name)
    {
        this.name=name;
    }
    public void speak()
    {
        System.out.println(this.name+"--"+this.age);
    }
    public static void showcountry()
    {
        System.out.println("country="+country);
    } 
 }
class PersonDemo
{
    public static void main(String []args)
    {
        Person p=new Person("heihei",10);
    }
}

Person p=new Person("heihei",10);

1.因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中(Person p=null 这种情况类不加载(new时会用到构造函数))

2.执行该类中的static代码块,如果有的话,给Person.class进行初始化。

3.在堆内存中开辟空间,分配内存地址。

4.在堆内存中建立对象的特有属性,并进行默认初始化。

5.对属性进行显示初始化。

6.对对象进行构造代码块初始化。

7.对对象进行对应的构造函数初始化。

8.将内存地址赋给栈内存中的p变量。

 

16.继承

特性:单继承(多继承安全隐患),支持多层继承

聚集 :has a

聚合:球队球员

组合:人体器官

提高代码的复用性,让类与类之间产生了关系,有了这个关系,才有了多态的特性。所属关系 :is a

如何使用一个继承体系中的功能:先查阅体系父类的描述,因为父类中定义的是该体系中共性功能,通过了解共性功能。就可以知道该体系的基本功能。在具体调用时,要创建最子类的对象,因为有可能父类不能创建对象(抽象类),创建子类对象可以使用更多功能。

当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖,保留父类的功能定义,并重写功能内容。

子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。(方法非属性)静态只能覆盖静态。

如果子类和父类中有同名属性,父类引用指向子类对象的时候,通过父类引用访问那个同名属性时,访问的是父类中的那个,不是子类中的那个,因为父类引用是看不到子类中的属性的,这和方法不同,父类引用调用子类方法时有个优先级的问题,this优先于super,即,如果子类中重写了父类的方法,那么调用的就是子类中的,如果没有重写,就调用的是父类中的。

public class tt 
{
   
    public static void main(String[] args) throws Exception{
       A b=new B(); //父类引用指向子类对象
       b.show();//输出bbbb
       System.out.print(b.num);//输出111
       int x=b.getnum();
       System.out.print(x);//输出333
       b.ss();//输出AAAA
    }
}
class A
{
	public int num=111;
	public void show()
	{
		System.out.print("aaaa");
	}
	public int getnum() {
		
		return num;
	}
	public void ss()
	{
		System.out.print("AAAA");
	}

}
class B extends A
{
	public int num=333;
	public int getnum()
	{
		return num;
	}
	public void show()
	{
		System.out.print("bbbb");
	}
}

 

 

 

17.super关键字

代表对父类对象的引用

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式语句 super();

super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super();

因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类时如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方法来指定。当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。

 

18.final关键字

final可以修饰类,方法,变量。

final修饰的类不可以被继承。

final修饰的方法不可以被覆盖。

final修饰的变量是一个常量,只能被赋值一次。

内部类只能访问被final修饰的局部变量。

 

19.abstract关键字

当多个类中出现相同功能,但是功能主体不同。这时可以进行向上抽取,这时,只抽取功能定义,而不抽取功能主体。

抽象类的特点:抽象方法一定在抽象类中,抽象方法和抽象类都必须被abstract关键字修饰,抽象类不可以用new创建对象,因为调用抽象方法没意义。抽象类中的方法要被使用必须由子类复写其所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

 

20.接口

可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示

不可以创建对象,因为有抽象方法,需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类。

一个类可以实现多个接口也是对多继承不支持的转换形式

class用于定义类

interface用于定义接口

接口定义时,格式特点:

接口中常见定义:常量,抽象方法

接口中的成员都有固定修饰符(自动+):常量:public static final

                                                方法:public abstract

接口中的成员都是public

类与类 继承 extends

类与接口 实现 implements

接口与接口 继承 extends(接口可以多继承)

 

21.多态

可以理解为事物存在的多种体现形态

猫 x=new 猫();

动物 x=new 猫();//类型提升,向上转型

体现:父类引用指向了自己的子类对象,父类引用也可以接收自己的子类对象

前提:类与类之间必须有关系,要么继承,要么实现

好处:提高程序的扩展性

弊端:只能使用父类的引用访问父类中的成员。

          如果子类和父类中有同名属性,父类引用指向子类对象的时候,通过父类引用访问那个同名属性时,访问的是父类中的那个,不是子类中的那个,因为父类引用是看不到子类中的属性的,这和方法不同,父类引用调用子类方法时有个优先级的问题,this优先于super,即,如果子类中重写了父类的方法,那么调用的就是子类中的,如果没有重写,就调用的是父类中的。

//如果想要调用子类的特有方法,就强制将父类的引用,转成子类类型
Animal a=new Cat();//向上转型
a.eat();
Cat c=(Cat)a;//向下转型
c.catchMouse();


//能转换的是父类引用指向自己的子类对象时,该引用可以被提升,也可以被强制转换
//多态自始至终都是子类对象在做着变化

Animal a=new Animal();
Cat c=(Cat)a;//这是不允许的

a instanceof Cat//判断a是否是Cat类型(判断所属类型)

在多态中成员函数(非静态)的特点:

在编译时期,参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,否则编译失败

在运行时期,参阅对象所属的类中是否有调用的方法

简单总结:非静态成员函数在多态调用时,编译看左边,运行看右边

                 静态成员函数,无论编译和运行,都参考左边

                 成员变量,无论编译和运行,都参考左边(引用型变量所属的类)

 

22.内部类

定义原则:当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。

 

内部类可以直接访问外部类中的成员,包括私有(因为内部类有默认引用 外部类.this)

外部类要访问内部类,必须建立内部类对象

其他类直接访问内部类: Outer.Inner in= new Outer().new Inner();

外部类与内部类出现同名变量时,内部类想要访问外部类变量:Outer.this.xxx;

 

内部类在成员位置上,就可以被成员修饰符所修饰

内部类定义在局部时,不可以被成员修饰符修饰

访问局部变量时,局部变量必须被final修饰

private :将内部类在外部类中进行封装

static:内部类具有静态特性(静态内部类),只能直接访问外部类中的静态成员

当内部类中定义了静态成员,该内部类必须是静态的

当外部类中的静态方法访问内部类时,内部类也必须是静态的

其他类访问静态内部类的非静态成员  new Outer.Inner().function();

其他类访问静态内部类的静态成员  Outer.Inner().function();

 

23.匿名内部类

匿名内部类其实就是内部类的简写格式。是一个匿名子类对象

前提:内部类必须是继承一个类或者实现接口

匿名内部类中定义的方法最好不要超过三个

abstract class AbsDemo
{
    abstract void show();
}
class Outer
{
    int x=3;
    /*
    class Inner extends AbsDemo
    {
        void show()
        {
            System.out.println(x);
        }
    }
    */
    public void function
    {
        //new Inner().show();

        new AbsDemo()//创建的是AbsDemo的子类,因为show方法被重写了
        {
            void show()
            {
                System.out.println(x);
            }
        }.show();
    }
}
interface Inter
{
    void method();
}
class Test
{
    public static Inter function()//1
    {
        return new Inter()
        {
            public void method()
            {
                System.out.println("haha");
            }
        };
    }
}
class TestDemo
{
    public static void main(String []args)
    {
        Test.function().method();//1
        

        show(new Inter()
        {
            public void method()
            {
                System.out.println("haha");
            }
        });//2
    }
    public static void show(Inter in)//2
    {
        in.method();
    }
}

 

24.异常

程序在运行时出现的不正常情况

异常由来:问题也是现实生活中一个具体的事物,也可以通过JAVA的类的形式进行描述,并封装成对象

                   其实就是java对不正常情况进行描述后的对象体现

问题划分:严重的 java通过Error类进行描述(一般不编写针对性的代码对其进行处理)

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

向上抽取 父类 Throwable

异常的处理:

try{  需要被检测的代码 }

catch( 异常类 变量 ){  处理异常的代码(处理方式) }      (Exception e = new XXXException())

finally{  一定会执行的语句 通常用于关闭资源(IO流 SQL连接)  }

          

声明异常:throws Exception 必须有try catch回应,否则编译失败,除非一直抛,直到抛给JVM处理。

声明异常时,简易声明更具体的异常 如除零 ArithmeticException

对方声明几个异常,就对应有几个catch块,不要定义多于的catch块。

如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

建议在进行catch处理时,一定要定义具体处理方式,不要简单定义一句e.printStackTrace语句。

 

自定义异常

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

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

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

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

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

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

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

throw和throws的区别:

throws使用在函数上                                                    throw使用在函数内

throws后面跟的是异常类,可以跟多个,用逗号隔开     throw后面跟的是异常对象

class FuShuException extends Exception
{
    private int value;
    FuShuException()
    {
        super();
    }
    FuShuException(String message,int value)
    {
        super(message);
        this.value=value;
    }
    public int getValue()
    {
        return value;
    }

}
class Demo 
{
    int div(int a,int b)throws FuShuException
    {
        if(b<0)
            throw new FuShuException("出现了除负数异常!!!",b);//手动通过throw关键字抛出自定义异常
        return a/b;
    }
}
class Test
{
    public static void main(String []args)
    {
        Demo d=new Demo();
        try
        {
            int x=d.div(4,-9);
            System.out.println(x);
        }
        catch(FuShuException e)
        {
            System.out.println(e.toString());
            System.out.println("错误的负数是"+e.getValue());
        }
    }
}

 

 

特殊异常:RuntimeException

Exception中有一个特殊的子类异常RuntimeException运行时异常

如果在函数内中抛出异常,函数可以不用声明,编译一样通过。

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

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

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

异常分两种

编译时被检测的异常

编译时不被检测的异常(RuntimeException及其子类)

 

异常在子父类覆盖中的体现:

1 子类在覆盖父类方法时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类,或者不抛(自己捕获异常并解决)

2 如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集

3 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常(如果子类方法发生了异常,就必须进行try处理,绝对不能抛)

 

总结

Ps:截图为毕向东老师Java基础视频。

 

 

25.包

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

编译:javac -d . PakeageDemo.java(-d 参数 包文件夹地址 (.为当前地址))

运行:java pack.PakeageDemo

总结:包与包之间进行访问,被访问的包中的类以及类中的成员,需要被public修饰

不同包中的子类还可以直接访问父类中被protected权限修饰的成员

 

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

//如果不import的话  pack.packzi.DemoB a=new pack.packzi.DemoB();

建议不写通配符* 需要使用哪个类。就导入哪个。

c:\myclass

c:\myclass\pack\DemoA.class

c:\myclass\pack\packzi\DemoB.class

import pack.*;               导入的是pack中的所有类,不包括packzi中的类

import pack.packzi.*;    导入的是packzi中的所有类

 

 

定包名不要重复,可以使用url来定义

import cn.itcast.demo

 

 

26.多线程

一个程序至少有一个进程,一个进程至少有一个线程

进程:是一个正在执行中的程序。每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。

一个进程中至少有一个线程。

Javac 编译时 会启动javac.exe 编译完成后关闭

Java VM 启动的时候会有一个进程java.exe

该进程至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。

JVM不止启动一个线程,还有负责垃圾回收机制的线程。

 

创建线程的第一种方式:继承Thread类

定义类继承Thread 重写Thread类中的run方法,调用线程的start方法(start方法启动线程并调用run方法)。

class Demo extends Thread
{
        Demo(String name)
        {
            super(name);//自定义线程名称
        }
        public void run()
        {
            System.out.print(this.getName());  
           // System.out.print(Thread.currentThread().getName());  Thread.currentThread() 获取当前线程的引用 建议使用这种方法
       }
}
main()
{
    Demo d=new Demo("xixi");//创建线程
    d.start();//启动线程 并调用run方法 则d这个线程和主线程就在“同时”运行(并发),出现随机性,CPU执行谁,谁执行。
    //d.run(); 如果直接调用run方法,而没有启动线程,run()中的代码执行完毕后主函数才会继续运行。
}

线程有默认名字 格式:Thread-编号 编号从0开始。

自定义线程名字 :构造函数或者setName()方法

多线程具有随机性,谁抢到谁执行。

线程的几种状态:

创建线程的第二种方式:实现Runnable接口

定义类实现Runnable接口,覆盖Runnable接口中的run方法,通过Thread类建立线程对象,将Runnable接口的子类对象作为

实际参数传递给Thread类的构造函数,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

 

继承方式和实现方式:建议使用实现方式,避免了单继承的局限性。

区别:继承---线程代码存放在Thread子类run方法中。

          实现---线程代码存放在接口子类run方法中。

 

多线程安全问题:  当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行时,导致共享数据的错误。

Java解决多线程的安全问题的方法:同步代码块/同步函数

 Object obj=new Object();

 synchronized(对象){}

哪些代码需要放进同步代码块中:

    明确哪些代码是多线程运行代码

    明确共享数据

    明确多线程运行代码中哪些语句是操作共享数据的

 

同步函数使用的锁是this

静态同步函数,使用的锁是该方法所在类的字节码文件对象  类名.class(静态方法中不可以定义this 静态进内存 内存中没有本类对象 但是一定有该类对应的字节码文件对象 所以该对象的类型是Class)

同步代码块

同步函数

同步函数

 

对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取了cpu的执行权,也进不去,因为没有获取锁

同步的前提:必须要有两个或者两个以上的线程,必须是多个线程使用一个锁

虽然同步代码块解决了多线程的安全问题,但多个线程都需要判断锁,较为消耗资源。

 

死锁:同步中含有同步

 

 

卖票:

public class TicketSale {

	public static void main(String[] args) {
		Ticket t1=new Ticket();
		Ticket t2=new Ticket();
		Ticket t3=new Ticket();
		Ticket t4=new Ticket();
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}
class Ticket extends Thread
{
	private static int tick=100;
	public void run()
	{
		while(tick>0)
		{
		    System.out.println(currentThread().getName()+"----"+tick--);
		}
	}
}
public class TicketSale {

	public static void main(String[] args) {
		Ticket t=new Ticket();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
	}

}
class Ticket implements Runnable
{
	private int tick=100;
        Object obj=new Object();
        public void run()
	{
		while(true)
		{
                     synchronized(obj)
                     {
                         if(tick>0)
                         {
                            System.out.println(Thread.currentThread().getName()+"----"+tick--);	
                         }
                     }	
		}
	}
}

 

 

多线程通信: 多个线程在操作同一个资源,但是操作的动作不同

 

 

wait() nitify() notifyAll()

都是用在同步中,因为要对持有监视器(锁)的线程操作。只有同步才具有锁。

为什么这些方法定义在Object类:因为这些方法在操作同步中线程时,都必须要标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,才可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。

而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中

 

 

 

 

优化:

 

生产者消费者:

多个生产者多个消费者

1.在判断flag时,用While不用if(每次被唤醒应重新判断flag 可能会导致生产两个 消费一个等不匹配情况,)

2.应使用notifyAll();(用notify可能导致所有线程都wait()。)

 

 

JDK1.5 提供了多线程升级方案

将同步Synchronized替换成显式Lock操作,将Object中的wait,notify,notifyALL替换成了Condition对象,该对象可以Lock锁进行获取,可以实现本方线程只唤醒对方线程的操作。

相关接口:Condition Lock

 

 

线程停止:

 

守护线程(后台线程):当当前线程都为守护线程时,自动结束。

 

 

Join:等待线程结束

 

 

27.String

字符串特点:一旦被初始化,就不可以被改变。存在于常量池。

String使用private final char value[ ]实现字符串的存储,也就是说String创建对象之后不能够再次修改此对象中存储的字符串内容

String s="abc";//s1是一个类类型变量,"abc"是一个对象

s="123"; //此时"abc"这个对象的内容并没有改变,只是s这个引用指向了另一个对象,即"123"


String类中重写了equals方法用于比较两个字符串的内容是否相等。(Java中也有其他类对equals进行了重写)

 

 

 

            一般情况    String类重写
==    比较内存地址    ------
equals   比较内存地址   比较内容

 

public class sss {
	public static void main(String []args)
	{
		String s1="aaa";
                String s2="aaa";
                String s3=new String("aaa");
                //s1和s3的区别
                  s1在内存中有一个对象
                  s2在内存中有两个对象
                System.out.println(s1==s2);//true  指向的是同一个对象
                System.out.println(s1==s3); //false  不是一个对象 内存地址不同
                System.out.println(s1.equals(s3));//true   不是一个对象,但内容相同
         }
}

 

字符串常用操作方法:

 

 

1.字符串去头尾空格:

2.字符串反转(或部分反转):

3.字串个数

4.获取最大相同字串

 

StringBuffer:

StringBuilder:单线程使用StringBuilder可提高效率

 

 

 

28.包装类

自动装箱拆箱:

 

29.集合

集合用来存储对象(内存地址),长度是可变的,可以存储不同类型对象。

Collection---List Set

List--- ArrayList LinkedList Vector

Set--- HashSet TreeSet

Iterator接口 迭代器:

 

 

30.List集合

元素是有序的,可以重复,集合有角标。

 

 

ArrayList:

 

LinkedList:

封装LinkedList到自己的类中:

队列/堆栈

Vector:

 

 

31.Set集合

元素无序(存入和取出的顺序不一定一致),且元素不能重复。

 

HashSet:

底层数据结构为哈希表,集合中元素的存的顺序为元素哈希值大小顺序。如果哈希值相同,在判断是否是同一对象(equals()),不是则顺延存入。

 

例子:

 

TreeSet

可以对Set集合中的元素进行排序,按ASCII顺序。 底层数据结构为二叉树

(1)对象类中自带比较

存对象时,需要实现Comparable接口中的唯一一个函数 compareTo()方法,并定义返回的int型,

返回负数,零,正数 分别代表 晓宇 等于 大于。等于时对象相等,不存入。主要条件相同时,判断次要条件。

如果想要实现按存入顺序取出的话,compareTo方法就一直返回正数。取出时默认从小到大取。

(2)TreeSet构造函数中传入比较器

定义自定义比较器类实现Comparator

对象和容器都有排序时,以容器的排序为主。

 

 

 

 

32.集合泛型

集合中使用泛型来约束集合中要存储的类类型

当类中要操作的引用数据类型不确定的时候,定义泛型类。(静态方法不能访问类上定义的类型,因为静态方法存在时,类还不存在)

方法也可以定义泛型。泛型放在返回值前面

接口也可以定义泛型

 

泛型限定

 

 

 

 

33.Map

 

HashMap

 

keySet:取出所有键存到Set中

entrySet:取出每一条数据映射关系存到Set中

 

 

34.Collections

工具类 里面的方法都是静态的 不需要创建对象

sort(List)  给list排序

sort(List,comparator<T>) 给list排序,并且自己定义比较器

binarySearch  二分法查询  不存在返回负插入点-1

fill(List,Object) 替换集合中的所有元素为Object

replaceAll(List , old, new) 将List中所有的old替换成new

reverse(List) 反转

reverseOrder(Comparator c) 返回一个逆转指定Comparator比较器顺序的比较器

synchronizedCollention(Collection c)  返回一个线程安全的集合

shuffle(List) 将List中的数据按随机源进行置换

 

 

35.Arrays

用于操作数组的工具类,里面全是静态类

asList() 将数组变成List集合,但是不可以使用集合的增删方法,因为数组的长度是固定的,如果增删了,会发生                        UnsupportedOperationException异常 。如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集            合中的元素,如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。(int数组与Integer                数组)

             可以使用集合的方法来操作数组,例如 contains,get,indexOf,subList等。

 集合也可转成数组-->list.toArray(new 数组类型[?])

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

              集合变数组是为了限定对元素的操作。不可增删。

 

sort()   排序 也可局部排序

binarySearch()  二分查询

fill()  替换 也可范围替换

toString()  将数组中元素按字符串形式输出

 

 

37.增强for循环

for(数据类型 变量名:被遍历的Collection(List Set)和数组 )

{

}

对集合进行遍历,但是不能对集合进行操作。

迭代器(Iterator)除了遍历,还可以remove集合中元素的动作。

如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

传统for循环和增强for循环有什么区别?

增强for循环有一个局限性,必须有被遍历的目标。

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

 

 

38.可变参数

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

在定义时,可变参数一定要定义在参数列表最后。

 

 

 

39.静态导入

StaticImport  静态导入

import static java.util.Arrays.*;导入这个类中所有静态成员----->数组工具类

import static java.lang.system.*;导入这个类中所有静态成员---->syso

当类名重名时,需要指定具体的包名。

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

 

 

40.System

描述系统的一些信息  类中的属性和方法都是静态的

out 标准输出 默认是控制台

in 标准输入 默认是键盘

arraycopy()  复制一个数组

exit()        终止虚拟机

currentTimeMillis()  获取当前时间的毫秒值

gc()   运行垃圾回收器

getProperties() 获取系统属性信息

可以自己将一些信息存到table中,随时取

 

 

41.Runtime

每一个JAVA应用程序都有一个Runtime类的实例,使应用程序能够与其运行的环境相连接。

没有构造函数,不能创建对象,类中函数全部都是非静态的。

所以它提供了一个函数来返回一个Runtime对象 getRuntime();----->单例设计

 

exec(String command)  在单独的进程中执行指定的字符串命令

Process  全是抽象方法,并且没有子类,由底层方法实现。

destroy()  杀掉子进程。

 

 

42.Date

表示特定的时间 精准到毫秒

 

Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));//2018-07-12 19:49:10
System.out.println(date.getTime());//1531396150467
System.out.println(date);//Thu Jul 12 19:49:10 CST 2018

 

 

43.Calendar

时间所有信息    单例 getInstance

DAY_OF_YEAR  ...

c.get(Calendar.YEAR)

 

 

44.Math Random

abs()  返回绝对值

ceil() 返回大于这个参数的最小整数

floor()  返回晓宇这个参数的最大整数

round()  四舍五入

pow(T x,T y)  x的y次幂

random()  返回   [0,1)的double伪随机数

 

 

 

45.IO流

字节流处理多媒体文件

字符流处理文本文件

 


流操作的基本规律
    流对象很多,不知道该用哪一个
通过三个明确来完成
1,明确源和目的
    源:输入流  InputStream  Reader
    目的:输出流 OutptStream  Writer
2,操作的数据是否是纯文本
    是:字符流
    不是:字节流

3,当体系明确后,再明确要使用哪个具体的对象
    通过设备来进行区分
    源:内存,硬盘,键盘
    目的:内存,硬盘,控制台

 

 

字节流的抽象基类:InputStream  OutputStream

字符流的抽象基类:Reader Writer

由这四个基类派生的子类都是以他们的名字作为后缀名。FileInputStream FileReader

 

IO异常处理方式

                FileWriter fw=null;
		try {
			fw=new FileWriter("demo.txt",true);//相对路径 创建对象  boolean append 
			fw.write("hahaha");//将字符串写入到流中
			fw.flush();//刷新流对象中的缓冲中的数据  将字符串刷新到目的地中
			
		} catch (IOException e) {
			
			System.out.println(e.getMessage());
		}
		finally
		{
			try {
				if(fw!=null)//判断fw是否初始化成功
					fw.close();//关闭流资源,在关闭前先刷新流对象
			} catch (IOException e2) {
				System.out.println(e2.toString());
			}
		}

 

 

字符流----->Reader Writer

FileWriter   该对象一被初始化,就必须要有被操作的文件

windows换行:\r\n   Linux换行:\n

FileWriter fw=new FileWriter("demo.txt",true);//相对路径 创建对象  boolean append 
fw.write("hahaha");//将字符串写入到流中
fw.flush();//刷新流对象中的缓冲中的数据  将字符串刷新到目的地中
fw.close();//关闭流资源,在关闭前先刷新流对象
	

 

FileReader

		//读取单个字符
                FileReader fr=new FileReader("demo.txt");
		try {
			fr=new FileReader("demo.txt");
			
			int c=fr.read();
			while(c!=-1)
			{
				System.out.print((char)c);
				c=fr.read();
			}
			
		} catch (IOException e) {
			
			System.out.println(e.getMessage());
		}
		finally
		{
			try {
				if(fr!=null)//判断fw是否初始化成功
					fr.close();//关闭该流并释放与之关联的所有资源。
			} catch (IOException e2) {
				System.out.println(e2.toString());
			}
		}

 

//通过字符数组进行读取
		FileReader fr=new FileReader("demo.txt");
		try {
			fr=new FileReader("demo.txt"); 
			
			int num=0;
			char[] buf=new char[1024];
			while((num=fr.read(buf))!=-1)
			{
				System.out.print(new String(buf,0,num));
			}
		
			
		} catch (IOException e) {
			
			System.out.println(e.getMessage());
		}
		finally
		{
			try {
				if(fr!=null)//判断fw是否初始化成功
					fr.close();//关闭流资源,在关闭前先刷新流对象
			} catch (IOException e2) {
				System.out.println(e2.toString());
			}
		}

复制文件
    

                FileWriter fw=null;
		FileReader fr=null;
		try {
			fw=new FileWriter("demo_copy.txt",true);
			fr=new FileReader("demo.txt"); 
			
			int len=0;
			char[] buf=new char[1024];
			
			while((len=fr.read(buf))!=-1)
			{
				fw.write(buf,0,len);
			}
		
			
		} catch (IOException e) {
			
			throw new RuntimeException("读写失败");
		}
		finally
		{
			if(fr!=null)
				try {				
						fr.close();									
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
			if(fw!=null)
				try {
					fw.close();//关闭流资源,在关闭前先刷新流对象
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
		}

 

 

缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用

BufferedWriter  BufferedReader

该缓冲区提供了一个换行方法  newLine();

该缓冲区提供了一次读一行的方法  方便对文本数据的读取  readLine();  返回null时  表示读到末尾  方法返回时只返回回车符之前的内容。不返回回车符。最终都是在硬盘上一个一个读取,所以最终还是使用read方法一次读一个的方法。其实readLine中有一个数组(长度足够),用read方法读取字符后存到数组中。

    

                FileWriter fw=null;
		FileReader fr=null;
		BufferedWriter bw=null;
		BufferedReader br=null;
		try {
			fw=new FileWriter("buf_copy.txt");
			bw=new BufferedWriter(fw);
			
			fr=new FileReader("buf.txt");
			br=new BufferedReader(fr);
			
			String str=null;	
			
			while((str=br.readLine())!=null)
			{
				
				bw.write(str);
				bw.newLine();
			}
			
			
		} catch (Exception e) {
			
		}
		finally {
				
			if(bw!=null)
				try {				
					bw.close();	//关闭缓冲区,就是在关闭缓冲区中的流对象								
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
			if(br!=null)
				try {				
					br.close();	//关闭缓冲区,就是在关闭缓冲区中的流对象								
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
			
		}

 

 

 

LineNumberReader

可获取行号  getLineNumber()

 

 

字节流------> InputStream   OutputStream

FileOutputStream    FileInputStream

字节流在不需要缓冲的情况下 不需要刷新

 

字节流复制文件

                FileInputStream fis=null;
		FileOutputStream fos=null;
		try {
			fis=new FileInputStream("buf.txt");
			fos=new FileOutputStream("buf_copy2.txt");
			
			byte[] buf=new byte[1024];
			int len=0;
			while((len=fis.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}

                         /*   这种方法是给数组分配正好空间的 只适用于操作小文件
			int length=fis.available();//获取文件中的大概字节数
			byte[] buf=new byte[length];
			fis.read(buf);
			fos.write(buf);
                        */
                } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			if(fis!=null)
				try {				
					fis.close();							
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
			if(fos!=null)
				try {				
					fos.close();							
				} catch (IOException e2) {
					System.out.println(e2.toString());
				}
		}

 

字节缓冲区流复制文件   

        FileInputStream fis=null;
        FileOutputStream fos=null;
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        try {
            fis=new FileInputStream("buf.txt");
            fos=new FileOutputStream("buf_copy2.txt",true);
            
            bis=new BufferedInputStream(fis);
            bos=new BufferedOutputStream(fos);
            
            int byt=0;
            byte[] bytt=new byte[1024];
            while((byt=bis.read(bytt))!=-1)
            {
                bos.write(bytt,0,byt);
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally
        {
            if(bis!=null)
                try {                
                    bis.close();                            
                } catch (IOException e2) {
                    System.out.println(e2.toString());
                }
            if(bos!=null)
                try {                
                    bos.close();                            
                } catch (IOException e2) {
                    System.out.println(e2.toString());
                }
        }

 

 

转换流

FileReader 默认编码表GBK
InputStreamReader  可指定编码表 要传入字节流 FileReader为该类的子类        
 

//键盘录入
        //获取键盘录入对象
        InputStream in=System.in;
        
        //将字节流对象转成字符流对象,使用转换流
        InputStreamReader isr=new InputStreamReader(in);
        
        //使用缓冲区高效操作字符串
        BufferedReader br=new BufferedReader(isr);
        
        
        OutputStream out=System.out;
        OutputStreamWriter osw=new OutputStreamWriter(out);
        BufferedWriter bw=new BufferedWriter(osw);
        
        String str=null;
        
        while((str=br.readLine())!=null)
        {    
            if("over".equals(str))
                break;
            bw.write(str);
            bw.newLine();
            bw.flush();
        }

 

 

46.异常的日志信息

System.setIn()  重新指定输入流
System.setOut()  重新指定输出流

异常的日志信息
 

//log4j
        try{
            int[] arr=new int[3];
            System.out.println(arr[3]);
        }
        catch(Exception e)
        {
            
            try{
                Date d=new Date();
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String date=sdf.format(d);
                
                PrintStream ps=new PrintStream("Exception.log");
                ps.println(date);
                System.setOut(ps);
                
            }
            catch(IOException e2)
            {
                throw new RuntimeException("日志文件创建失败");
            }
            
            e.printStackTrace(System.out);
            //e.printStackTrace(new PrintStream("Exception.log"));
        }
       

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值