zoukankan      html  css  js  c++  java
  • java之类 下

    包装类

    java时面向对象的语言,但是还是有8种不是继承至object的数据类型。因此java提供了包装类,将这几种基本类型,自动装箱成类实例。

    当然自动装箱只能是类型匹配才可以。

    还提供了基本类型和字符串之间的转换。parseXxx(string)和string.valueof()。

    其中比较大小时,当integer 类型,超过128时,会出现问题。

    java7增加了compare方法。

    java8增加了无符号运算方法,也为Byte,Short增加了toUnsignedInt()、toUnsignedLong(方法。

    处理对象

    toString方法,是object类里就有的方法。如果直接使用,则会打印“类名+@+hashCode”值,因此我们一般重写toString方法。

    ==和equals

    jvm会使用常量池来管理在编译时被确定并被保存在一编译的.class文件中的一些数据。

    因此var str="hello" 与var str2=new String(“hello”)是不一样的,前者字符串hello保存在常量池中,后者则先在常量池中保存一份hello,然后再调用String构造器创建一个新的String对象,这个对象被保存在堆内存中。因此两个不相同。

    当用==判断时,输出false。

    jvm保证相同的字符串直接量只有一个,不会产生副本,则只要在编译时就能确定的常量,则只有一个。

    例如

    var a1=“你好” var a2=“你”+“好” 则a1和a2是jvm中一个对象。如果,var a4=“你”,var a5=“好”,var a3=a4+a5,则a3在编译时不能确定值,所以被保存在运行时堆内存中,因此两者==的话会false。

    equals方法,是object类提供的一个实例方法,因此所有引用变量都可以调用。但是,只是比较对象的地址也就是说个方法同样是判断两个引用变量是不是指向同一个对象。因此没有太大的意义,同样需要重写。

    instanceof 当前面对象是后面对象的子类时也都返回true,而xxx.getClass()==YYY.class 时,则是同一个类,不能是子类或者父类。

    equals方法要满足以下条件

    1.自反性: x.equals(x)一定为true

    2、对称性

    3.传递性

    4.一致性,无论调用多少次,结果一样。

    5.对任何不是null的类型,x.equals(null)一定返回false

    类成员

    类成员包括成员变量、方法、构造器、初始化块、内部类(包括接口,枚举)5种成员。

    static可以修饰出构造器以外的4种成员,加了static以后,属于类不属于实例。

    单例类

    有时候不允许其他类自由的创建某个类的实例,比如说只能有一个窗口页面。那么这时候,就需要将构造器隐藏起来。但是隐藏构造器以后,当要获取该类的时候,就需要有一个公共的方法,因为还没有实例,所以该方法必须是static,由于只能有一个实例,所以需要有一个保存实例的变量,用来保证只有一个实例,因为要在static方法中访问这个变量,因此这个变量也要定为static。

    final修饰符

    final可以修饰类,变量和方法。类似于c#的sealed,表示类,方法,变量的不可变。

    final成员变量

    包括类变量和实例变量。

    类变量,只能在静态初始化块或者声明时期显示的指定初值,必须二者之一。

    实例变量,只能在普通初始化块,声明时期,构造器三者之一显示指定初值。但是只有哦在定义时为该变量赋初值,才会有“宏变量”的效果。

    如果使用构造器或者初始化块来为final成员变量赋值,则不要在这之前访问他,如果直接访问,会出错,如果用方法访问,java允许通过方法访问final变量,但这会导致系统为他赋默认的值。

    final局部变量

    局部变量可以在定义时指定初始值,也可以不指定,在后面代码中指定,只可以指定一次。也可以作为形参、

    final修饰基本类型变量,则变量值不允许改变

    final修饰引用类型变量,则地址不可以改变,但是引用的内容可以改变。

    对于final变量,

    只要在定义final变量是指定了初始值,并且该初始值在编译时就可以确定下来。那么这个变量就相当于直接量。存在jvm的常量池中。这种叫做宏变量。

    final方法

    final方法不能被子类重写,例如object类里的getClass方法。但是可以重载。

    final修饰私有的方法,则在子类中可以定义类似重写的方法。

    final类

    final类不可以有子类

    不可变类

    创建该类实例以后,该实例的实例变量不可以改变。java的8个包装类和java.lang.String都是不可变类。

    自定义不可变类:

    使用private和final修饰符来修饰该类的成员变量。

    提供带参数的构造器或者返回该实例的类方法,用于根据传入参数初始化类里的成员变量。

    仅为该类的实例变量提供getter方法。

    如果有必要,重写hashCode方法和equals方法。要保证两个用equals方法判断相等的对象,其hasCode也相等。

    当不可变类里面有引用类型的成员变量,即使使用final修饰,但是final只保证了变量的地址不能改变,其引用的内存可以改变,因此会造成不可变类变成可变类。

    这时就需要,当初始化时,传入的引用变量,不能直接在构造函数中赋值,因为如果这个引用变量改变以后,会导致类的成员变量变化,所以必须为这个变量重新开辟一个内存,复制一份。将这个复制品给类的成员变量复制。这样,就不会出现,改掉引用对象的值,同时改掉类成员变量的情况了。

    缓存实例的不可变类

    如果程序经常使用相同的不可变类的实例,应该考虑将之放入缓存中。节省系统开销。

    java的integer方法,如果采用new构造器创建对象则不会启用缓存机制,若采用valueof,则采用缓存机制,产生实例。

     抽象类

    抽象方法只有方法签名,没有方法实现。当一个类只知道子类需要有什么方法,但又不知道子类如何实现。那么就定义抽象方法。

    有抽象方法的类,一定必须定义为抽象类。但是抽象类可以没有抽象方法。两者都用abstract修饰符定义。

    抽象方法不能有方法体

    抽象类不能实例化对象。

    抽象类可以包含成员变量,方法,初始化块,构造器,内部类。抽象类的构造器不能用于创建实例,主要用于被其子类调用。

    含抽象方法的类(包括直接定义了抽象方法,继承了一个抽象父类,但没有完全实现父类包含的抽象方法,实现了一个接口,但没有完全实现接口包含的抽象方法)都只能被定义为抽象类。

    抽象类,不能创建实例,但是可以引用其子类的非抽象类的实例,并调用子类实现(重写)的抽象方法。这是多态的应用。

    因为final,不能被继承,不能被重写,因此final和abstract永远不能在一起。static和abstract也不能一起修饰一个方法,即没有抽象类方法。abstract也不能修饰成员变量,局部变量,构造器。但是abstract和static可以同时修饰内部类。

    abstract和private不能同时修饰类方法。

    接口

    修饰符可以是public也可以省略,省略以后默认包权限访问。

    一个接口可以继承多个接口,但不能继承类。

    接口不能包含构造器和初始化块。

    接口可以包含静态常量,方法只能是抽象方法,类方法,默认方法,或者私有方法。

    除去私有方法,其他的变量,方法都是public访问权限。

    私有方法为默认方法或者类方法提供支持,不可以default修饰。可以static修饰。私有方法可以是类方法也可以是成员方法。

    对于静态常量,系统默认为static fianl 也就是说,接口中定义成员变量时,自动public static final 因此,只能是定义时初始化。

    接口里的方法如果不是类方法、默认方法、私有方法,则默认public abstract修饰。

    接口里的内部类,内部接口,内部枚举都采用public static进行修饰。

    接口的默认方法其实就是实例方法,因为java8以前不允许实例方法有方法体,所以就重新定义了一个默认方法,默认方法就是有方法体的实例方法。默认为pubic

    类方法,必须用static修饰,也是java8以后才允许在接口中定义的,不能用default修饰。默认public

    默认方法有实现接口的类的实例调用,类方法可以接口直接调用。

    java8的默认方法,所以java9引入了私有方法。因为如果默认方法里有同样的代码,就需要抽离出来,定义成私有的方法。

    接口里的成员变量默认public static final 因此另外一个处于不同包下,通过接口来访问接口里的成员变量。

    接口支持多继承

    接口可以声明变量,但是这个变量必须引用实现接口的类的实例。

    可以调用接口中的常量。

    可以让类实现。

    类实现接口,需要加implements。一个类可以实现多个接口。implements必须写在extends后面。

    实现接口的方法时,只能使用public,因为子类实现父类的方法时,访问权限只能更大或者相等。

    接口和抽象类

    都不能被实例化,用于被其他类实现和继承。

    都包含抽象方法,实现或者继承的类都必须实现这些抽象方法。

    接口体现的是一中规范。对于接口的实现者,接口规定了必须向外界提供哪些服务。对于接口的调用者,接口体现了调用者·可以调用哪些方法,怎么样调用。接口是多个模块的耦合标准。是多个程序之间的通讯。

    抽象类是类的模板,。】

    接口只能包括抽象方法,私有方法,默认方法,静态方法。而抽象类可以由普通方法。

    接口只能定义静态常量。抽象类则可以普通变量。

    接口不包含构造器和初始化块。抽象类可以包含构造器和初始化块(让其子类使用)

    一个类只能有一个父类,包括抽象类。但是可以由多个接口。

    面向接口编程

    工厂模式

    让类A与接口耦合,使用工厂类,生成实现接口的类的实例。然后让类A使用工厂类获得实现了接口的类的实例。这样当需要改变类时,只需要改变工厂类的方法。

    命令模式

    类似于函数回调。

    内部类

    内部类是定义在另一个类里的类,也叫嵌套类。

    提供了更好的封装,只有宿主类可以访问,同一个包里的其他类不能访问。

    内部类的成员可以直接访问外部类的私有数据,外部类不能访问内部类的实现细节。

    内部类可以使用private,protected,static。

    非晶态内部类不允许有静态成员。

    大部分内部类作为成员内部类,输入类的成员。

    局部内部类和匿名内部类不属于成员。

    成员内部类有两种:非静态内部类和静态内部类

    非静态内部类

    编译时,会生成OuterClass$InnerClass.class文件

    非静态内部类可以直接访问外部类的私有成员,因为在非静态内部类里保存了一个他所寄生的外部类的对象的引用。当调用非静态内部类时,必须有一个非静态内部类实例。非必须寄生在外中。

    如果内部类的成员变量和外部类里的成员变量同名,则可以通过使用this,外部类名.this作为限定来区分。

    不允许非静态内部类包含静态方法。

    静态内部类
    静态内部类不能访问外部类的非静态成员,静态内部类的实例也不行。因为静态类时与类相关的,与外部类的实例不相关,所以不能访问实例变量。

    外部类的方法,初始化块都可以使用静态类。

    外部类不能直接访问静态类中的成员,必须用静态内部类的类名访问或者实例访问。

    java允许接口里定义内部类,默认修饰符是public static。

    在外部类以外使用非静态内部类

    private访问控制符修饰的内部类,只能在外部类内部使用

    protected访问控制符修饰的内部类,可被与外部类处于同一包中的其他类和外部类的子类访问。

    public,可在任何地方被访问。

    省略访问控制符的内部类,只可与外部类处于同一包中的其他类访问。

    在外部类以外的地方创建非静态内部类实例必须使用外部类实例和new 来调用非静态内部类的构造器。

    非静态内部类的构造器必须通过外部类的实例来调用。

    这一点在创建非静态内部类的子类是尤为关键

    需要 outer.super. 调用非静态内部类的构造器。

    非静态内部类和其子类,都必须持有指向外部类对象的引用。区别在于,创建非静内部类实例是outer调用new方法。创建器子类是outer调用构造器。

    非静态的内部类的子类不一定是内部类,也可以是外部类,但是其实例一样需要有其父类的外部类的实例。也就是说有一个内部类子类的对象存在,则一定有一个与之对应的外部类的对象。

    静态内部类的使用

    因为静态内部类是类相关的。因此区别于非静态内部类,需要外部类的实例来调用new,只需要外部类即可调用构造器。

    局部内部类

    局部内部类作用域在函数块内,因此没有访问控制符。

    定义局部内部类后,编译后会生成outerclass$1innerclass.class文件。数字的原因是局部内部类可能出现同名。

    匿名内部类

    匿名内部类必须实现一个接口,但只能继承一个父类或者接口。

    匿名内部类不是抽象类,因为创建匿名内部类就好立马创建其对象。因此不允许是抽象类。

    匿名内部类不能定义构造器。没有类名,所以无法定义构造器。

    匿名内部类,其实就是为了命令模式,作为函数指针使用

    当创建匿名内部类时,如果匿名类是实现接口的,则只有默认的构造器,new的时候没有参数。

    如果是继承抽象类的匿名类,则需要传递抽象类构造器的参数。

    匿名内部类鼻血实现接口或者抽象类的所有抽象方法,如果有必要,还可以重写抽象类中的普通方法。

    java8以前的版本,只有被局部内部类或者匿名内部类访问的局部变量,必须使用final修饰符。java8以后可以不用,但必须按照有final修饰理解。如果再次对局部变量赋值,将会导致错误。

    java11增强的Lambda表达式

    函数式接口:只有一个抽象方法的接口。

    lambda表达式主要作用是代替匿名内部类的繁琐语法。

    形参列表。可以省略类型,如果只有一个形参可以省略括号。

    箭头->,不同于c#是=>,

    代码块,如果代码值包括一条语句,允许省略花括号。如果需要返回值,而代码块只有一条语句,则返回这条语句的值,不用写return。

    lambda表达式会被当成一个“任意类型”的对象。

    lambda表达式与函数式接口

    lambda表达式的类型,也被称为“目标类型”,lambda表达式的目标类型必须是“函数式接口”。函数式接口可以包含多个默认方法,类方法,但只能有一个抽象方法。

    lambda表达式只能为函数式接口创建对象。

    lambda表达式赋值给函数式接口类型的变量。

    作为函数式接口类型的参数传给某个方法。

    使用函数式接口对lambda表达式进行强制转换。

    lambda表达式对var赋值时,必须制定函数值接口类型。

    var run= (Runnable)()->{。。。}

    java11 运行var来声明lambda表达式的形参类型。在java11以前,必须严格声明每个参数的类型。

    方法引用与构造器引用

    1.lambda表达式只有一行调用类方法的代码,那么可以使用类名::类方法代替。

    2.如果只有一行特定对象调用实例方法的代码,可以使用特定对象::实例方法。

    3如果只有一行某类对象调用实例方法的代码,可以类名::实例方法。函数式接口中,第一个参数作为调用者,后面的作为实例方法的参数。

    4.如果只有一行对某个类的构造器调用看,则可以类名::new代替。函数式接口中的参数,决定了调用类的哪个构造器。

    lambda表达式与匿名内部类的区别和联系。

    两者都可以方法final局部变量和外部类的成员变量。

    两者都可以直接调用接口中继承的默认方法。

    匿名内部类,可以为任意接口实现实例,但lambda表达式只能为函数式接口实现实例。

    匿名内部类可以为抽象类或者普通类创建实例,但是lambda只能为函数式接口实现实例。

    匿名内部类实现实例的抽象方法的方法体中可以调用接口中定义的默认方法,但是lambda不允许。

    枚举类

    实例有限而且固定的类,被称为枚举类。

    枚举类可以实现一个或者多个接口,用enum定义。枚举类继承了java.lang.Enum类,因此不能显示继承其他父类。

    非抽象的枚举类默认使用final修饰。

    枚举类构造器只能使用private访问控制符。因此不能派生子类。

    枚举类的所有实例,必须在枚举类的第一行显示列出,系统 默认添加public static final修饰符,否则这个枚举类永远不能产生实例。

    枚举类默认提供一个values方法。遍历所有枚举值。

    当为枚举类显示定义了带参数的构造器。则列出枚举值时候,必须对应地传入参数。

    枚举类可以实现接口,普通的实现方式,每个枚举值在调用方法时都有相同的行为方式。

    可以这样实现接口

    public enum Gender implements GenderDesc{
    MALE("男"){
    public void info(){
    Systme.out.println(“这个枚举值代表男性”)
    }
    },
    FEMALE("女"){
    public void info(){
    Systme.out.println(“这个枚举值代表女性”)
    }
    };
    

     其中枚举值后面花括号的部分其实是匿名内部类,而枚举值相当于匿名内部类的实例。编译此程序时,会生成,Gender.class,Gender$1.class,Gender$2.class.三个文件。

    这样当调用不同的枚举值时候,会调用不同的函数。

    不是所有的枚举类都使用了final修饰。抽象的枚举类,(只包含了抽象方法)他就是以abstract修饰。

    枚举类里定义了抽象方法时,不能显示的为枚举类添加abstract修饰符,系统默认添加。

    因为枚举类是需要显示的创建枚举值,而不是作为父类,所以在定义每个枚举值后面必须为抽象方法提供实现(匿名内部类),否则将出错。

    对象与垃圾回收

    垃圾回事对象之前,会先调用它的finalize方法。这个方法中如果让一个引用变量重新引用该对象,则复活了该对象,从而导致垃圾回收机制取消。

    对象在内存中有可达状态(对象创建以后,有变量引用)可恢复状态(不在有任何变量引用,当调用finalize方法时可以恢复)

    不可达状态(与所有变量切断,并且调用了finalize方法,依然没有使他变为可达状态,则不可达,这时系统才会真正回收他)

    强制垃圾回收

    System。gc()

    Runtime..getRuntime.gc()。

    永远不要主动调用finalize方法,交给垃圾回收机制调用

    此方法何时调用,是否调用具有不确定性。可以在调用gc以后,强制调用,Runtime.getRuntime.runFinalization或者System.runFinalization。

    jvm执行可恢复对象的finalize方法时,可能使该对象或者系统中其他对象重新变成可达状态。

    jvm执行finalize方法异常时,垃圾回收机制不会报告异常,程序继续执行

    对象的软、弱和虚引用

    java对象有4种引用

    1.StrongReference强引用

    最常见的引用方式,当一个对象被一个或几个变量强引用时,不能被垃圾回收机制回收、

    2.SortReference软引用

    软引用必须通过softreference类实现,当一个对象只被软引用,它有可能被垃圾回收,当系统空间足够,可能不回收。通常用于对内存敏感的程序中。

    3WeakReference弱引用

    必须使用weakreference类实现,比软引用级别更低,当系统垃圾回收机制运行时,不论空间内存是否足够,总会被回收。

    4PhantomReference虚引用

    必须通过PhantomReference类实现,虚引用完全类似于没有引用。对本身没太大影响。主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列ReferenceQueue联合使用。

    三个类都有get方法,用来获取被他们所引用的对象。

  • 相关阅读:
    oracle的row_number()和rownum
    linux视频学习6(mysql的安装/)
    linux视频学习5(top, 网络监控
    linux视频学习4(crontab和进程)
    linux的视频学习4(网络配置和rpm)
    linux视频学习3(shell和网络)
    linux视频学习3(linux安装,shell,tcp/ip协议,网络配置)
    linux(视频学习)2
    linux视频学习(简单介绍)20160405
    java代码用dom4j解析xml文件的简单操作
  • 原文地址:https://www.cnblogs.com/tomato190/p/12327154.html
Copyright © 2011-2022 走看看