Object类相关面向对象编程的三大特性:封装、继承、多态。
实现多态的三个必要条件:继承、重写、向上转型。
实现形式:
父类的静态方法可以被子类继承,但是不能被子类重写。
当子类声明了一个与父类相同的静态方法时,只能称为隐藏。
/**
* @author lizejun
**/
public class Parent {
public static void staticMethod() {
System.out.println("Parent Static Method");
}
public void method() {
System.out.println("Parent Method");
}
}
/**
* @author lizejun
**/
public class Child extends Parent {
public static void staticMethod() {
System.out.println("Child Static Method");
}
public void method() {
System.out.println("Child Method");
}
}
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
Parent parent = new Child();
parent.method();
parent.staticMethod();
Child child = new Child();
child.method();
child.staticMethod();
}
}
Child Method
Parent Static Method
Child Method
Child Static Method
在Java中,分为基本数据类型和复合数据类型,基本数据类型包括byte、short、char、int、long、float、double、boolean这八种。
==比较的是它们的值。Object中equals默认的实现是比较两个对象是不是==,和==的效果是相同的。
public boolean equals(Object obj) {
return (this == obj);
}
而有些时候,对于两个不同的对象,我们又需要提供 逻辑 上是否相等的判断方法,这时候就需要重写equals方法。Java提供的某些类已经重写了equals方法,用于判断"相等"的逻辑,例如Integer。
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
hashCode的目的是用于在对象进行散列的时候作为key输入,保证散列的存取性能。Object的默认hashCode实现为在对象的内存地址上经过特点的算法计算出。
由此可见,equals和hashCode的其实没有什么关系。但是由于HashSet/HashMap容器的存在,又需要保证:
equals相等两个对象,其hashCode返回的值一定相等equals不同的对象要尽量做到hashCode不同。在 Java&Android 基础知识梳理(8) - 容器类 中提到的HashMap的实现,value替换的条件是判断key:
//Value 替换的条件
//条件1:hash 值完全相同
//条件2:key 指向同一块内存地址 或者 key 的 equals 方法返回为 true
(e.hash == hash && ((k = e.key) == key || key.equals(k)))
假如我们只重写了equals方法,而没有重写hashCode方法,就会导致逻辑上相等的两个key,放在了容器中的不同位置。
int属于基本数据类型,存储在栈中。Integer属于复合数据类型,引用存储在栈中,引用所指向的对象存储在堆中。0null泛型支持Integer,不支持int
//基本数据类型。
int a1 = 128;
//非 new 出来的 Integer。
Integer a2 = 128;
//new 出来的 Integer。
Integer a3 = new Integer(128);
new出来的Integer与new出来的Integer不相等,前者指向存放它的常量池(数值位于-128到127之间)或者堆,后者指向堆中的另外一块内存。new出来的Integer,如果在-128到127之间,返回的是true,否则返回的是false,因为Java在编译Integer a2 = 128的时候,会翻译成Integer.valueOf(128),而valueOf函数会对-128到127之间的数进行缓存。 public static Integer valueOf(int i) {
//low = -128, high = 127.
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
new出来的,返回false。int与Integer相比,都为true,因为会把Integer自动拆箱为int再去比较。new String和直接赋值的区别:
String str1 = "ABC",可能创建一个或者不创建对象,如果ABC这个字符串在常量池中已经存在了,那么str1直接指向这个常量池中的对象。String str2 = new String("ABC"),至少创建一个对象。一定会在堆中创建一个str2中的String对象,它的value是ABC,如果ABC这个字符串在常量池中不存在,会在池中创建一个对象。String s ="a" + "b" + "c" + "d"
只创建了一个对象,在编译器在编译时优化后,相当于直接定义了一个abcd的字符串。
String ab = "ab";
String cd = "cd";
String abcd = ab + cd;
String s = "abcd";
ab和cd存储的是两个常量池中的对象,当执行ab + cd时,首先会在堆中创建一个StringBuilder类,同时用ab指向的字符串对象完成初始化,然后调用append方法完成对cd指向字符串的合并操作,接着调用StringBuilder的toString方法在堆中创建一个String对象,最后将刚生成的String对象的地址存放在局部变量abcd中。
String中的是常量数组,只能被赋值一次。String/StringBuffer对象,直接使用字符串常量的+效率更高。StringBuffer中的value[]是一个很普通的数组,而且可以通过append方法将新字符串加入到末尾,改变内容和大小。StringBuffer允许多线程操作,其很多方法都被关键字synchronized修饰,而StringBuilder则不是,如果不考虑线程安全,StringBuilder应该是首选。String对象。String的intern时,如果常量池已经有了当前String的值,那么返回这个常量指向的地址;如果没有,则将String值加入到常量池中。字符串常量池是Java堆内存的一个特殊区域,当创建一个String对象时,假如字符串已经存在于常量池中,则不会创建新的对象,而是直接引用已经存在的对象。
String s1 = "abc";
String s2 = "abc";
s1和s2指向常量池中的同一个对象abc,如果String是可变类,s1对其的修改将会影响到s2。
因为字符串不可变,在创建的时候HashCode就被缓存,不需要重新计算。
由多个线程之间共享,不需要同步处理。
public的方法都是复制一份数据String是final,因此不可继承copy而不是直接将value[]赋值给内部变量。final可以用于以下四个地方:
final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的。final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的。被final修饰的变量必须被初始化,初始化的方式有以下几种:
final变量在初始化块中初始化,不可在静态初始化块中初始化final变量可以在静态初始化块中初始化。final变量可以在类的构造器中初始化,但是静态final变量不可以不可以被子类重写,但是不影响被子类继承。
不允许被继承。
this的。static成员变量的初始化顺序按照定义的顺序进行初始化。static块可以置于类的任何地方,类中可以有多个static块。static块的顺序来执行每个static块,并且只执行一次。内部类的定义:在一个外部类的内部再定义一个类。
static的内部类,成员内部类不能有static数据和static方法,但嵌套内部类可以。final。外部顶级类即类名和文件名相同的只能使用public和default修饰,但内部类可以是static、public/default/protected/private。
首先,定义内部类需要实现的接口:
/**
* @author lizejun
**/
public interface InnerInterface {
void call();
}
再定义一个包装类:
/**
* @author lizejun
**/
public class Outer {
private class InnerImpl implements InnerInterface {
@Override
public void call() {
System.out.println("call inner");
}
}
public InnerInterface getInnerInterface() {
return new InnerImpl();
}
}
由于我们将InnerInterface的实现类声明为了private,因此外部并不知道它的存在,也就达到了隐藏的目的。
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
Outer outer = new Outer();
InnerInterface inner = outer.getInnerInterface();
inner.call();
}
}
/**
* @author lizejun
**/
public class Outer {
//外部类的私有变量。
private int outerSelfValue = 0;
private class InnerImpl implements InnerInterface {
@Override
public void call() {
//内部类可以无条件地访问。
System.out.println("call inner, outerValue=" + outerSelfValue);
}
}
public InnerInterface getInnerInterface() {
return new InnerImpl();
}
}
这仅限于非静态内部类,它和静态内部类的区别是:
Outer.InnerImpl outer = new Outer().new InnerImpl();;静态内部类则可以直接创建,Outer.InnerImpl outer = new Outer.InnerImpl();
由于Java不允许多重继承,因此假如我们希望一个类同时具备其它两个类的功能时,就可以采用内部类来实现。
实现乘法的子类:
/**
* @author lizejun
**/
public class MultiCalculator {
public int multi(int a, int b) {
return a * b;
}
}
实现加法的子类:
/**
* @author lizejun
**/
public class PlusCalculator {
public int add(int a, int b) {
return a;
}
}
/**
* @author lizejun
**/
public class Calculator extends PlusCalculator {
class MultiCalculatorImpl extends MultiCalculator {
@Override
public int multi(int a, int b) {
return super.multi(a, b);
}
}
public int multi(int a, int b) {
return new MultiCalculatorImpl().multi(a, b);
}
}
用于解决下面的困境:一个需要继承另一个类,还要实现一个接口,而继承的类和接口里面有两个同名的方法。那么我们调用该方法的时候,究竟是父类的,还是实现的接口呢,这时候就可以使用内部类来解决这一问题。
call方法/**
* @author lizejun
**/
public class BaseOuter {
public void call() {
System.out.println("call baseOuter");
}
}
call方法/**
* @author lizejun
**/
public interface InnerInterface {
void call();
}
/**
* @author lizejun
**/
public class Outer extends BaseOuter {
private class InnerImpl implements InnerInterface {
@Override
public void call() {
//内部类可以无条件地访问。
System.out.println("call inner");
}
}
public InnerInterface getInnerInterface() {
return new InnerImpl();
}
}
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
Outer outer = new Outer();
//1. 调用的是继承父类的接口。
outer.call();
//2. 调用的实现接口的方法。
outer.getInnerInterface().call();
}
}
/**
* @author lizejun
**/
public interface InnerWorker {
void work();
}
/**
* @author lizejun
**/
public class Factory {
public void doWork(InnerWorker worker) {
try {
worker.work();
} catch (Exception exception) {
System.out.println("exception!");
} finally {
System.out.println("finally!");
}
}
}
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
Factory factory = new Factory();
factory.doWork(new InnerWorker() {
@Override
public void work() {
System.out.println("work1 work");
}
});
factory.doWork(new InnerWorker() {
@Override
public void work() {
System.out.println("work2 work");
}
});
}
}
/**
* @author lizejun
**/
public interface Shape {
void draw();
}
/**
* @author lizejun
**/
public abstract class ShapeFactory {
private static HashMap<String, ShapeFactory> factories = new HashMap();
public static void addFactory(String id, ShapeFactory factory) {
factories.put(id, factory);
}
public static Shape createShape(String id) {
if (!factories.containsKey(id)) {
try {
Class.forName(id);
} catch (Exception e) {}
}
return factories.get(id).create();
}
protected abstract Shape create();
}
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
Shape shape = ShapeFactory.createShape(Circle.ID);
shape.draw();
}
}
闭包就是把函数以及变量包起来,使得变量的生存周期延长,闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的。
涉及到闭包的两种内部是:局部内部类和匿名内部类。当它们引用外部变量时,外部的变量需要是final的。
以下面这个例子为例,定义一个内部类的接口:
/**
* @author lizejun
**/
public interface InnerInterface {
void call();
}
/**
* @author lizejun
**/
public class InnerClose {
public void doClose(final int a) {
InnerInterface inner = new InnerInterface() {
@Override
public void call() {
System.out.println("a=" + a);
}
};
inner.call();
}
}
/**
* @author lizejun
*/
public class MainApp {
public static void main(String[] args) {
InnerClose close = new InnerClose();
close.doClose(1);
}
}
在编译之后,局部内部类会生成独立的InnerClose$1.class文件,而变量a是方法级别的,方法运行完变量就销毁了,而局部内部类对象还可能一直存在,不会随着方法运行结束就马上被销毁。这时候就会出现,局部内部类对象需要访问一个已经不存在的局部变量a。
因此,通过将变量声明为final,编译器会将final局部变量复制一份,复制品作为局部内部类中的成员,这样,当局部内部类访问局部变量时,其实真正访问的是这个局部变量的复制品。
由于被final修饰的变量赋值后不能再修改,所以就保证了复制品与原始变量的一致,就好像是局部变量的 生命期变长了,这就是Java的闭包。
在既需要统一的接口,又需要实例变量或缺省方法的情况下,可以使用:
8bit,所以能表示的字符范围是0~255个。char,从char到byte必须编码。ASCII码总共有128个,用一个字节的低7位表示。
在ASCII码基础上制定了一系列标准来扩展ASCII编码,其仍然是单字节编码,总共能表示256个字符。
双字节编码,总的范围是A1~F7,从A1~A9是符号区,总共包含682个符号;从B0~F7是汉字区,包含6763个汉字。
扩展GB2312,加入更多的汉字,其编码范围是8140~FEFE,和GB2312兼容。
我国的强制标准,可能是单字节、双字节或者四字节编码,与GB2312兼容。
ISO试图创建一个全新的语言字典,将所有的语言互相翻译。String在内存中 不需要编码格式,它只是一个Unicode字符串而已。只有当字符串需要在网络中传输或要被写入文件时,才需要编码格式。
UTF-16UTF-16具体定义了Unicode字符在计算机中的存取方法,它用两个字节表示Unicode转化格式。UTF-8UTF-16的缺点在于很大部分字符仅用一个字节就可以表示,目前却需要使用两个,而UTF-8采用了变长技术,不同类型的字符可以由1~6个字节组成。
0,表示这是一个ASCII字符。11开头,连续的1个数表示这个字符的字节数。10开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节。String s = "严";
//编码。
byte[] b = s.getBytes("UTF-8");
//解码。
String n = new String(b,"UTF-8");
GB2312与GBK编码规则类似,但是GBK范围更大,它能处理所有汉字字符。UTF-16和UTF-8都是处理Unicode编码,UTF-16效率更高,它适合在本地磁盘和内存之间使用。UTF-16不是在网络之间传输,因为网络传输容易损坏字节流,UTF-8更适合网络传输,对ASCII字符采用单字节存储,单字节损毁不会影响后面其它字符。Java中定义了许多异常类,并定义了Throwable作为所有异常的超类,将异常划分为两类Error和Exception。
Error:程序中无法处理的错误,例如NoClassDefFoundError、OutOfMemory等,当此类错误发生时,JVM将终止进程。Exception:程序本身可以处理的异常。
RuntimeException及其子类,表示JVM在运行时可能出现的错误,例如空指针、数组越界等,一般是由逻辑错误引起。RuntimeException及其子类的异常。编译器会检查此类异常,并提示你处理本类异常 - 要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。Java&Android 基础知识梳理(4) - 垃圾收集器与内存分配策略
Java&Android 基础知识梳理(5) - 类加载&对象实例化
Java & Android 基础知识梳理(12) - 泛型
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear