写Java的文章在网上太多太多,随便一搜都是你抄我我抄你的代码,要么就是讲一些旁门左道学了一辈子都用不上的玩意,又或是太基础太基础,基础到看完文章什么都没学会,什么也没学到。本篇是我的Java专栏第三篇,看过我前两篇专栏的同学一定知道我讲的东西是别人没讲过且很实用的内容,比起那些看起来又冗长又浪费时间的文章而言,希望你可以从我的专栏中学到受益的技能和受到思维的启发。如果喜欢我的内容,请继续关注我的专栏,本专栏从Java基础、集合、内存GC、IO、多线程、JVM以及性能优化7个方面剖析Java,旨在帮助有一定Java开发经验的程序员提高自己。如有问题,可在我的专栏底部给我留言,我会尽我的能力给你解答。
今天我给大家讲讲不一样的Java OOP。其实内容也很基础,本来想放在上一篇文章里讲的,但是又不想让文章变得冗长,因此分篇介绍。
众所周知面向对象有三大特性,继承/封装和多态,这里我如果还讲这些就对不起大家了,浪费大家时间了。我给大家讲讲OOP的第四大特性 抽象 ,下次去面试的时候可以在考官面前炫耀炫耀。抽象类和接口是面向对象的高级特性,是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征。使用关键词abstrace声明的类叫做“抽象类”。
刚刚提到过面向对象高级特性除了抽象类,还有接口。
在Java中类只能单继承,但是接口却支持多继承:
interface A { int YES = 1; int NO = 2; a(); } interface B { int SUMMER = 3; int WINTER = 4; b(); } interface c extends A, B { c(); }
实际开发中会遇到一种情况,如果想要在旧的接口文件中加一个方法,那么所有该接口的实现类都需要修改。在 JAVA8 中,允许在接口中定义一个默认方法,让实现类可以不用实现该方法,类似于抽象类中的方法。
interface MyInterface { void a(); default String getMyName() { return "H3c"; } }
当一个类需要实现MyInterface接口时,必须实现a()方法,但是他可以选择是否重写getMyName()方法,即使不重写也可以正常调用getMyName()方法。
因为抽象方法需要依赖子类重写,静态方法无法被重写,native方法需要具体实现,synchronized类同。
常见的内部类有内部类、静态内部类、匿名内部类。其实还存在一种更为隐蔽的局部内部类:
void myMethod() { class LocalInnerClass { ... } }
以上示例中LocalInnerClass类仅供myMehtod方法访问。
System类表示当前Java程序运行的平台。Runtime类表示当前Java程序运行时环境。
跟System.gc()一样,也存在Runtime.getRuntime().gc()方法,实际上System.gc()就是调用的Runtime.gc()方法。
通过System.getevn()方法可以获取当前系统的平台环境变量;通过System.getProperties()方法可以获取当前系统属性。例如:
// 通过该方法可以获得浏览器UA // Dalvik/2.1.0 (Linux; U; Android 7.0; SM-G9350 Build/NRD90M) System.getProperty("http.agent")
通过Runtime可以获得JVM相关信息,如CPU数量,内存信息。
// 获得CPU个数 Runtime.getRuntime().availableProcessors(); // 获得已使用内存大小 Runtime.getRuntime().totalMemory(); // 获得剩余内存大小 Runtime.getRuntime().freeMemory(); // 获得总内存大小 Runtime.getRuntime().maxMemory();
通过以上这个例子,我们发现freeM总是很小,原因是Java程序只有当内存不够用的时候才会向内存申请内存,totalM是已经占用的内存,freeM是申请到还没用到的内存,因此占用内存大小是totalM+freeM<maxM,当超过maxM的时候就会报OOM。在Android上一个App最大可用内存大小是 512M 。
Runtime还可以单独启动一个进程来执行控制台命令:
Runtime.getRuntime().exec("notepad.exe");
strictfp表示精确浮点,使类采用更精确的浮点计算方法。
transient表示变量不会被持久化。
初始化块分为静态初始化块和普通初始化块。static初始化块会在构造函数之前执行,且只会执行一次。普通初始化块也会在构造函数之前执行,但是每次调用构造函数之前都会执行。特别注意,非静态代码块是紧跟着构造函数执行的,中间不会插其他代码。
```
public class A {
static {
print("父类静态代码块");
}