必须掌握的Java基础知识(二)

抽象类

抽象类和抽象方法必须使用abstract修饰符,有抽象方法的类只能够定义称为抽象类,抽象类中可以没有抽象方法。抽象方法没有方法体。抽象类不能够被实例化,因此无法使用new创建对象。

直接定义一个抽象方法,或者继承抽象父类没有完全实现父类的所有抽象方法,或者没有实现接口中所有的抽象方法。这三种情况的类只能够定义为抽象类。

抽象类中可以包括构造方法和成员变量、初始化模块、内部类,这是为子类服务的,这些是在创建子类对象时被调用的。所以利用抽象方法和抽象类更好地能够发挥多态的优势。

abstract和final永远不可以同时使用。

static和abstract不能够同时修饰同一个方法。

抽象类体现的是模板模式的设计,抽象类作为子类的通用模板,子类在抽象类的基础上进行扩展、改造、但子类大致保留了抽象类的行为方式。

接口

修饰符可以是public也可以省略,默认是相同包结构下才可以访问该接口。

接口内不能有构造器和初始化模块,接口里的成员变量只能是静态常量,方法只能是抽象实例方法,类方法和默认方法。接口里的常量,默认是public static final int MAX_SIZE = 50;系统自动为增加public static final

接口里的方法总是默认public abstract修饰。在接口里定义默认方法需要使用default修饰,此时可以有方法体。接口里定义类方法需要使用static修饰。

同一包下可以使用接口名访问该接口中的成员。接口名.成员变量

接口支持多继承。即改善了类单继承的缺点。

接口和抽象类

接口和抽象类都不能被实例化。接口和抽象类都可以包含抽象方法,实现接口和抽象类的普通子类必须要实现所有的抽象方法。

抽象类中完全可以包含普通方法。接口里只能定义静态常量,而抽象类既能够定义普通成员变量,又能够定义静态常量。接口里不能有构造器,而抽象类可以包含构造器。接口里不能有初始化块,而抽象类可以有初始化块。

简单工厂模式利用面向接口编程思想来降低程序的耦合性。

命令式模式,pa.process(target,new addCommond());传入的参数为数组对象和接口的实现类。

内部类

内部类能够访问外部类的私有数据,内部类被当做是外部类的成员,但是外部类不能够访问内部类的成员。

匿名内部类适合用于那些需要一次使用的类。

内部类比外部类可以多使用三个修饰符:private、protected、static。

非静态内部类不能够拥有静态成员。

编译后,有两个class文件。OuterClass.class  和   OuterClass$InnerClass.class

外部类成员变量、内部类成员变量和内部类方法的局部变量相同时怎么分别访问?

外部类名.this.变量名                 this.变量名                    变量名

外部类需要访问非静态内部类的成员变量,则必须显式创建非静态内部类对象来访问其实例成员。

外部类的静态成员中不能直接使用非静态内部类。

Java不允许在非静态内部类定义静态成员。

静态内部类

静态内部类属于外部类本身,不属于外部类的某个对象。因此又叫做类内部类。

静态内部类不能访问外部实例成员。只能访问外部类的类成员。

外部类访问静态内部类的成员变量和类变量,静态内部类名.类成员                new  静态内部类名().实例成员

在外部类以外使用非静态内部类    Out.In in = new Out().new In();//必须通过创建外部类对象来调用内部类构造器来创建对象。

在外部类以外使用静态内部类         Out.In in = new Out. In();静态内部类属于外部类本身成员,直接使用外部类类名创建内部类对象。

局部内部类

内部类定义在一个方法的里面。

编译后:

LocalInner.class 外部类  、LocalInner$1InnerBase.class 局部内部类父类 、LocalInner$1InnerSub.class局部内部类子类 

在不同方法中的局部内部类可以同名,因此class文件命名规则使用$N来区分。

匿名内部类

只适合那种需要使用一次的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能够重复使用。

匿名内部类必须实现一个借口或者继续继承一个父类。它不是抽象类,因为它能够创建实例,就不能够将匿名内部类定义成抽象类。没有类名,当然也不允许存在构造器,使用初始化块来完成需要完成的事情。

Java8之前如果局部变量被局部内部类后者匿名内部类访问,必须使用final。Java8更智能,相当于自动添加了final修饰符。如果在①后添加age=2;就会编译错误,因为被匿名类访问的局部变量被final修饰了,不能再进行赋值操作。

interface A{ void test()}
public class ATest{
    public static void main(){
        int age = 8;//①如果局部变量被局部内部类后者匿名内部类访问,默认使用final
        A a = new A(){
            public test(){
                System.out.println(age);
            }
        };
        a.test();
    }
}

Java8新特性Lambda表达式

Lambda表达式允许代码块作为方法的参数,使用更简洁的代码来创建只有一个抽象方法的接口的实例,该接口被称作函数式接口。Lambda的表达式就相当于一个匿名方法,能够代替匿名内部类繁琐的语法。主要有三个部分组成:形参列表、箭头和代码块。Lambda表达式的代码块只有一条语句可以省略花括号,形参列表只有一个参数可以省略小括号,代码块只有一条语句,即使需要return返回值,也可以省略return。

Lambda表达式的类型,也可被称为目标性,目标类型必须是函数式接口。都有哪些函数式接口呢?Runnable,ActionListener等。

Lambda表达式结果被当做对象,所以可以进行赋值,且必须明确该表达式的类型为函数式接口,可以强制转换为函数式接口。

Java8在java.util.function包下定义了大量的函数式接口,4类。

XxxFunction:apply方法接收并返回一个新值,用于对指定数据进行转换。

XxxConsumer:accept抽象方法进行处理,不返回结果。

XxxPredicate:test抽象方法进行判断,返回Boolean类型的结果。

XxxSupplier:getAsXxx抽象方法。

方法引用和构造器引用:Lambda表达式的代码块只有一条代码时。

1引用类方法

类名:方法名  ---------------------------------------------(a,b..)-> 类名.类方法(a,b...)

@FunctionInterface
interface Converter{
    Integer converter(String from);
}

Converter converter1 = from -> Integer.valueOf(from);

Converter converter1 =  Integer::valueOf;

2引用特定对象的实例方法

Converter converter2 = from -> "adfaadgag".valueOf(from);


Integer value = converter2.converter("fa");

System.out.println(value);//结果为2

"使用引用替换上面的代码"
Converter converter2 =  "adfaadgag"::valueOf;

3引用某类对象的实例方法

类名:实例方法  ---------------------------------------------(a,b..)-> a.实例方法(b...)

@FunctionInterface
interface MyTest{
    String test(String a, int b, int c);
}

MyTest mt = (a,b,c)->a.substring(b,c);

String str = mt.test(Java I Love You,2,9);
System.out.println(str);//结果为va I Lo

"方法引用代替Lambda表达式:引用某个对象的实例方法"
MyTest mt = String::substring;

4引用构造器

YourTest yt = (String a)->new JFrame(a);

YourTest yt = JFrame::new;

对象与垃圾回收

垃圾回收只负责堆内存的对象,不会后手任何物理资源(数据库连接、网络IO等资源)

程序无法精准控制垃圾回收的运行,垃圾回收会在何时的时候进行。垃圾回收之前总会调用finalize方法,该方法使得该对象重新被一个变量引用,从而导致垃圾回收机制取消。

对象在内存的三个状态:可达状态,可恢复状态和不可达状态(垃圾回收)。当一个对象失去引用后系统何时调用finalize方法对它们进行资源整理,何时它变成不可达状态,系统何时回收它所占用的内存,对于程序完全透明。程序只能控制一个对象何时不再被任何引用变量引用,绝不可能控制何时回收它

强制垃圾回收的两种方式:

调用System类的gc()静态方法:System.gc();

调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc();

finalize是Object的实例方法,永远不要调用某个对象的finalize方法,该方法应该交给垃圾回收机制调用。该方法何时被调用你何时执行具有不确定性,JVM执行可恢复对象的finalize方法,可以是该对象变成可达状态。当JVM执行finalize方法出现异常时,垃圾回收机制不会报告异常,程序继续执行。

System类:

获得系统当前时间的两个方法1currentTimeMills()和2nanoTime().

identityHashCode(Object o):该方法指定对象的精确hashcode的值。当某个累的hashCode方法重写后,该类实例的hashCode()的方法就不能唯一标识该对象。但是identityHashCode值相同,则一定是同一个对象。

Runtime类

Runtime run = Runtime.getRuntime();

run.availableProcessors();获得处理器的数量

run.freeMemory();获得空闲内存

run.totalMemory();获得总内存

run.maxMemory();获得可用的最大内存

ThreadLocalRandom和Random

在并发访问的情况下,使用ThreadLocalRandom来代替Random可以减少多线程资源竞争,最终保证系统具有更好的线程安全性。当两个Random的种子相同时,Random r1 = new Random(50);Random r2 = new Random(50); 他们会产生相同的数字序列,所以一般使用System.currentTimeMills()作为Random对象的种子,而不是用具体的数字。

ThreadLocalRandom random =  new ThreadLocalRandom.current();

int val1 = random.nextInt(4,20);//产生一个4~20的为随机整数

double val2 = random.nextDouble(1.0,10.0);//产生一个1.0~10.0的为随机浮点数

BigDecimal类

float和double类型的数据进行算术运算时,精度容易丢失。

注意:使用new BigDecimal(String s)构造器创建对象。一定是用String对象作为参数,不能直接使用double数字作为参数传入,这样降低运算精度。可以使用静态方法BigDecimal.valueOf(double val)获得BigDecimal对象。

如果要求对double浮点数进行算术运算,首先BigDecimal.valueOf(double val)获得BigDecimal对象,利用BigDecimal提供的加减乘除进行运算得到BigDecimal类型,最后转换成double类型的结果。

方法如下:

 

 

 

发布了17 篇原创文章 · 获赞 11 · 访问量 8403
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览