-
Kotlin学习之接口、数据类和单例类
2021-01-03 17:30:36我们都知道,Java是单继承结构的语言,任何一个类最多只能继承一个父类,但是却可以实现任意多个接口,Kotlin也是如此。 我们可以在接口中定义一系列的抽象行为,然后由具体的类去实现。下面还是通过具体的代码来...接口
接口是用于实现多态编程的重要组成部分。我们都知道,Java是单继承结构的语言,任何一个类最多只能继承一个父类,但是却可以实现任意多个接口,Kotlin也是如此。
我们可以在接口中定义一系列的抽象行为,然后由具体的类去实现。下面还是通过具体的代码来学习一下,首先创建一个Study接口,并在其中定义几个学习行为。右击包→New→Kotlin File/Class,在弹出的对话框中输入“Study”,创建类型选择“Interface”。
然后在Study接口中添加几个学习相关的函数,注意接口中的函数不要求有函数体,代码如下所示:
interface Study { fun readBooks() fun doHomework() }
接下来就可以让Student类去实现Study接口了,这里我将Student类原有的代码调整了一下,以突出继承父类和实现接口的区别:
class Student(name: String, age: Int) : Person(name, age), Study { override fun readBooks() { println(name + " is reading.") } override fun doHomework() { println(name + " is doing homework.") } }
熟悉Java的人一定知道,Java中继承使用的关键字是extends,实现接口使用的关键字是implements,而Kotlin中统一使用冒号,中间用逗号进行分隔。上述代码表示Student类继承了Person类,同时还实现了Study接口。另外接口的后面不用加上括号,因为它没有构造函数可以去调用。
Study接口中定义了readBooks()和doHomework()这两个待实现函数,因此Student类必须实现这两个函数。
现在我们可以在main()函数中编写如下代码来调用这两个接口中的函数:
fun main() { val student = Student("Jack", 19) doStudy(student) } fun doStudy(study: Study) { study.readBooks() study.doHomework() }
首先创建了一个Student类的实例,本来是可以直接调用该实例的readBooks()和doHomework()函数的,但是我没有这么做,而是将它传入到了doStudy()函数中。doStudy()函数接收一个Study类型的参数,由于Student类实现了Study接口,因此Student类的实例是可以传递给doStudy()函数的,接下来我们调用了Study接口的readBooks()和doHomework()函数,这种就叫作面向接口编程,也可以称为多态。
现在运行一下代码,结果如图2.20所示。
为了让接口的功能更加灵活,Kotlin还增加了一个额外的功能:允许对接口中定义的函数进行默认实现。其实Java在JDK 1.8之后也开始支持这个功能了,因此总体来说,Kotlin和Java在接口方面的功能仍然是一模一样的。
下面我们学习一下如何对接口中的函数进行默认实现,修改Study接口中的代码,如下所示:
interface Study { fun readBooks() fun doHomework() { println("do homework default implementation.") } }
可以看到,我们给doHomework()函数加上了函数体,并且在里面打印了一行日志,成为它的默认实现。现在当一个类去实现Study接口时,只会强制要求实现readBooks()函数,而doHomework()函数则可以自由选择实现或者不实现,不实现时就会自动使用默认的实现逻辑。
现在回到Student类当中,你会发现如果我们删除了doHomework()函数,代码是不会提示错误的,而删除readBooks()函数则不行。
接下来我们再学习一个和Java相比变化比较大的部分——函数的可见性修饰符。
熟悉Java的人一定知道,Java中有public、private、protected和default(什么都不写)这4种函数可见性修饰符。Kotlin中也有4种,分别是public、private、protected和internal,需要使用哪种修饰符时,直接定义在fun关键字的前面即可。
下面我详细介绍一下Java和Kotlin中这些函数可见性修饰符的异同。
首先private修饰符在两种语言中的作用是一模一样的,都表示只对当前类内部可见。public修饰符的作用虽然也是一致的,表示对所有类都可见,但是在Kotlin中public修饰符是默认项,而在Java中default才是默认项。
protected关键字在Java中表示对当前类、子类和同一包路径下的类可见,在Kotlin中则表示只对当前类和子类可见。Kotlin抛弃了Java中的default可见性(同一包路径下的类可见),引入了一种新的可见性概念,只对同一模块中的类可见,使用的是internal修饰符。
数据类与单例类
1.数据类
在一个规范的系统架构中,数据类通常占据着非常重要的角色,它们用于将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。
数据类通常需要重写equals()、hashCode()、toString()这几个方法。
这里我们新构建一个手机数据类,字段就简单一点,只有品牌和价格这两个字段。如果使用Java来实现这样一个数据类,代码就需要这样写:
public class Cellphone { String brand; double price; public Cellphone(String brand, double price) { this.brand = brand; this.price = price; } @Override public boolean equals(Object obj) { if (obj instanceof Cellphone) { Cellphone other = (Cellphone) obj; return other.brand.equals(brand) && other.price == price; } return false; } @Override public int hashCode() { return brand.hashCode() + (int) price; } @Override public String toString() {java return "Cellphone(brand=" + brand + ", price=" + price + ")"; } }
而同样的功能使用Kotlin来实现就会变得极其简单,右击包→New→Kotlin File/Class,在弹出的对话框中输入“Cellphone”,创建类型选择“Class”。然后在创建的类中编写如下代码:
data class Cellphone(val brand: String, val price: Double)
你没看错,只需要一行代码就可以实现了!神奇的地方就在于data这个关键字,当在一个类前面声明了data关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量。
另外,当一个类中没有任何代码时,还可以将尾部的大括号省略。
下面我们来测试一下这个数据类,在main()函数中编写如下代码:
fun main() { val cellphone1 = Cellphone("Samsung", 1299.99) val cellphone2 = Cellphone("Samsung", 1299.99) println(cellphone1) println("cellphone1 equals cellphone2 " + (cellphone1 == cellphone2)) }
这里我们创建了两个Cellphone对象,首先直接将第一个对象打印出来,然后判断这两个对象是否相等。运行一下程序,结果如图所示。
2.单例类
想必你一定听说过单例模式吧,这是最常用、最基础的设计模式之一,它可以用于避免创建重复的对象。比如我们希望某个类在全局最多只能拥有一个实例,这时就可以使用单例模式。当然单例模式也有很多种写法,这里就演示一种最常见的Java写法吧:
public class Singleton { private static Singleton instance; private Singleton() {} public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } public void singletonTest() { System.out.println("singletonTest is called."); } }
这段代码其实很好理解,首先为了禁止外部创建Singleton的实例,我们需要用private关键字将Singleton的构造函数私有化,然后给外部提供了一个getInstance()静态方法用于获取Singleton的实例。在getInstance()方法中,我们判断如果当前缓存的Singleton实例为null,就创建一个新的实例,否则直接返回缓存的实例即可,这就是单例模式的工作机制。
而如果我们想调用单例类中的方法,也很简单,比如想调用上述的singletonTest()方法,就可以这样写:
Singleton singleton = Singleton.getInstance(); singleton.singletonTest();
虽然Java中的单例实现并不复杂,但是Kotlin明显做得更好,它同样是将一些固定的、重复的逻辑实现隐藏了起来,只暴露给我们最简单方便的用法。
在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。现在我们尝试创建一个Kotlin版的Singleton单例类,右击包→New→Kotlin File/Class,在弹出的对话框中输入“Singleton”,创建类型选择“Object”,点击“OK”完成创建,初始代码如下所示:
object Singleton { }
现在Singleton就已经是一个单例类了,我们可以直接在这个类中编写需要的函数,比如加入一个singletonTest()函数:
object Singleton { fun singletonTest() { println("singletonTest is called.") } }
可以看到,在Kotlin中我们不需要私有化构造函数,也不需要提供getInstance()这样的静态方法,只需要把class关键字改成object关键字,一个单例类就创建完成了。而调用单例类中的函数也很简单,比较类似于Java中静态方法的调用方式:
Singleton.singletonTest()
这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例,并且保证全局只会存在一个Singleton实例。
()这样的静态方法,只需要把class关键字改成object关键字,一个单例类就创建完成了。而调用单例类中的函数也很简单,比较类似于Java中静态方法的调用方式:
Singleton.singletonTest()
这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例,并且保证全局只会存在一个Singleton实例。
本文章参考自郭霖的第一行代码——Android(第3版)
-
Java中抽象类和接口区别
2017-03-21 10:35:141.一个类可以实现多个接口 ,但却只能继承最多一个抽象类。 2.抽象类可以包含具体的方法 , 接口的所有方法都是抽象的。 3.抽象类可以声明和使用字段 ,接口则不能,但接口可以创建静态的final常量。 4....简单概括下Java中抽象类和接口直接的区别,可以概括为如下几点:
1.一个类可以实现多个接口 ,但却只能继承最多一个抽象类。
2.抽象类可以包含具体的方法 , 接口的所有方法都是抽象的。
3.抽象类可以声明和使用字段 ,接口则不能,但接口可以创建静态的final常量。
4.接口的方法都是public的,抽象类的方法可以是public,protected,private或者默认的package;
5.抽象类可以定义构造函数,接口却不能。
-
抽象类与接口的三点区别
2010-03-13 16:08:00在使用上,一个不包含非抽象方法的抽象类与接口是类似的,不过请注意以下几点1:一个类可以实现任意多个接口,但它最多只能继承一个抽象类2:一个抽象类可以含有诺干个非抽象方法,它通常是模板方法模式的一个实例.而一个...在使用上,一个不包含非抽象方法的抽象类与接口是类似的,不过请注意以下几点
1:一个类可以实现任意多个接口,但它最多只能继承一个抽象类
2:一个抽象类可以含有诺干个非抽象方法,它通常是模板方法模式的一个实例.而一个接口的所有方法都是抽象的,无论是否将它的方法显示地声明为抽象.
3:一个抽象类可以声明实例变量,其子类可以继承这些实例变量.而一个接口不能声明实例变量,不过接口可以声明static final修饰的域。
4:一个抽象类可以定义构造方法,而接口不能。
5:一个抽象类的可见性修饰符可以是public,protected,private,或者无修饰符(表示包内可见);而一个接口的可见性修饰符只能是public,或者无修饰符(表示包内可见)
6:一个抽象类的方法的可见性修饰符可以是protected,private,或者无修饰符(表示包内可见);
而一个接口的方法的可见性修饰符只能是public.
7:一个抽象类是从Object类派生而来的,它继承了Object类的clone()方法和equals()方法。
例:
package com.oozinoz.simulation;
import com.oozinoz.units.*;
interface RocketSim()
{
abstract Length appgee();
public Force thrust();
}
下面的表述正确的是?
A: RocketSim接口中的两个方法都是抽象方法,尽管只有apogee()方法显式地声明为抽象的
正确,接口的方法总是抽象的,无论是否显式地声明
B: RocketSim接口中的两个方法都是公共方法,尽管只有thrust()方法显式地声明为公共的
正确,接口的方法总是公共的,无论是否显式地声明。
C: 所有接口都是公共的,所以RocketSim也是公共的,尽管它没有显式地声明为公共的
错误,该接口的可见性受限于其所在的包,RocketSim接口没有显式地声明为public,因而它在包内可见,com.oozinoz.sim包之外的其他类是无法访问或实现该接口的。
D: 可以再创建一个接口,如RocketSimSolid接口,并扩张RocketSim接口。
正确,例如,List接口和Set接口都扩展了java.util包中的Collection接口。
E: 每个接口必须至少含有一个方法
错误,不含方法的接口被称作标记(market)接口
F:接口可以声明实例域,实现该接口的类,也必须声明该域。
错误,一个接口不能声明实例域,不过它可以通过声明static和final修饰的域来声明常量
G:虽然不能实例化一个接口,但接口定义可以声明构造器方法,要求实现该接口的类必须提供具有指定参数的构造器的方法。
错误,接口不可以定义构造方法
-
我用的最多的三种模式
2020-05-15 15:04:16关于策略模式的使用方式,在Spring中其实比较简单,从本质上讲,策略模式就是一个接口下有多个实现类,而每种实现类会处理某一种情况。 我们以发奖励为例进行讲解,比如我们在抽奖系统中,有多种奖励方式可供选择,...策略模式
关于策略模式的使用方式,在Spring中其实比较简单,从本质上讲,策略模式就是一个接口下有多个实现类,而每种实现类会处理某一种情况。
我们以发奖励为例进行讲解,比如我们在抽奖系统中,有多种奖励方式可供选择,比如积分,虚拟币和现金等。在存储时,我们必然会使用一个类似于type的字段用于表征这几种发放奖励的,那么这里我们就可以使用多态的方式进行奖励的发放。比如我们抽象出一个PrizeSender的接口,其声明如下:public interface PrizeSender { /** * 用于判断当前实例是否支持当前奖励的发放 */ boolean support(SendPrizeRequest request); /** * 发放奖励 */ void sendPrize(SendPrizeRequest request); }
该接口中主要有两个方法:support()和sendPrize(),其中support()方法主要用于判断各个子类是否支持当前类型数据的处理,而sendPrize()则主要是用于进行具体的业务处理的,比如这里奖励的发放。下面就是我们三种不同类型的奖励发放的具体代码:
// 积分发放 @Component public class PointSender implements PrizeSender { @Override public boolean support(SendPrizeRequest request) { return request.getPrizeType() == PrizeTypeEnum.POINT; } @Override public void sendPrize(SendPrizeRequest request) { System.out.println("发放积分"); } }
// 虚拟币发放 @Component public class VirtualCurrencySender implements PrizeSender { @Override public boolean support(SendPrizeRequest request) { return PrizeTypeEnum.VIRTUAL_CURRENCY == request.getPrizeType(); } @Override public void sendPrize(SendPrizeRequest request) { System.out.println("发放虚拟币"); } }
// 现金发放 @Component public class CashSender implements PrizeSender { @Override public boolean support(SendPrizeRequest request) { return PrizeTypeEnum.CASH == request.getPrizeType(); } @Override public void sendPrize(SendPrizeRequest request) { System.out.println("发放现金"); } }
这里可以看到,在每种子类型中,我们只需要在support()方法中通过request的某个参数来控制当前request是否是当前实例能够处理的类型,如果是,则外层的控制逻辑就会将request交给当前实例进行处理。关于这个类的设计,有几个点需要注意:
1、使用@Component注解对当前类进行标注,将其声明为Spring容器所管理的一个bean;
2、声明一个返回boolean值的类似于support()的方法,通过这个方法来控制当前实例是否为处理目标request的实例;
3、声明一个类似于sendPrize()的方法用于处理业务逻辑,当然根据各个业务的不同声明的方法名肯定是不同的,这里只是一个对统一的业务处理的抽象;
4、无论是support()方法还是sendPrize()方法,都需要传一个对象进行,而不是简简单单的基本类型的变量,这样做的好处是后续如果要在Request中新增字段,那么就不需要修改接口的定义和已经实现的各个子类的逻辑;参考我的这篇项目重构,我是如何优化大量屎一样的 if else 代码的
工厂方法模式
上面我们讲解了如何使用Spring来声明一个策略模式,那么如何为不同的业务逻辑来注入不同的bean呢,或者说外层的控制逻辑是什么样的,这里我们就可以使用工厂方法模式了。
所谓的工厂方法模式,就是定义一个工厂方法,通过传入的参数,返回某个实例,然后通过该实例来处理后续的业务逻辑。一般的,工厂方法的返回值类型是一个接口类型,而选择具体子类实例的逻辑则封装到了工厂方法中了。通过这种方式,来将外层调用逻辑与具体的子类的获取逻辑进行分离。如下图展示了工厂方法模式的一个示意图:
可以看到,工厂方法将具体实例的选择进行了封装,而客户端,也就是我们的调用方只需要调用工厂的具体方法获取到具体的事例即可,而不需要管具体的实例实现是什么。
上面我们讲解了Spring中是如何使用策略模式声明处理逻辑的,而没有讲如何选择具体的策略,这里我们就可以使用工厂方法模式。
如下是我们声明的一个PrizeSenderFactory:@Component public class PrizeSenderFactory { @Autowired private List<PrizeSender> prizeSenders; public PrizeSender getPrizeSender(SendPrizeRequest request) { for (PrizeSender prizeSender : prizeSenders) { if (prizeSender.support(request)) { return prizeSender; } } throw new UnsupportedOperationException("unsupported request: " + request); } }
这里我们声明一个了一个工厂方法getPrizeSender(),其入参就是SendPrizeRequest,而返回值是某个实现了PrizeSender接口的实例,可以看到,通过这种方式,我们将具体的选择方式下移到了具体的子类中的,因为当前实现了PrizeSender的bean是否支持当前request的处理,是由具体的子类实现的。
在该工厂方法中,我们也没有任何与具体子类相关的逻辑,也就是说,该类实际上是可以动态检测新加入的子类实例的。这主要是通过Spring的自动注入来实现的,主要是因为我们这里注入的是一个List,也就是说,如果有新的PrizeSender的子类实例,只要其是Spring所管理的,那么都会被注入到这里来。下面就是我们编写的一段用于测试的代码来模拟调用方的调用:
@Service public class ApplicationService { @Autowired private PrizeSenderFactory prizeSenderFactory; public void mockedClient() { SendPrizeRequest request = new SendPrizeRequest(); request.setPrizeType(PrizeTypeEnum.POINT); // 这里的request一般是根据数据库或外部调用来生成的 PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request); prizeSender.sendPrize(request); } }
在客户端代码中,首先通过PrizeSenderFactory获取一个PrizeSender实例,然后通过其sendPrize()方法发放具体的奖励,通过这种方式,将具体的奖励发放逻辑与客户端调用进行了解耦。而且根据前面的讲解,我们也知道,如果新增了一种奖励方式,我们只需要声明一个新的实现了PrizeSender的bean即可,而不需要对现有代码进行任何修改。
Builder模式
关于Builder模式,我想使用过lombok的同学肯定会说builder模式非常的简单,只需要在某个bean上使用@Builder注解进行声明即可,lombok可以自动帮我们将其声明为一个Builder的bean。关于这种使用方式,本人不置可否,不过就我的理解,这里主要有两个点我们需要理解:
1、Builder模式就其名称而言,是一个构建者,我更倾向于将其理解为通过一定的参数,通过一定的业务逻辑来最终生成某个对象。如果仅仅只是使用lombok的这种方式,其本质上也还是创建了一个简单的bean,这个与通过getter和setter方式构建一个bean是没有什么大的区别的;
2、在Spring框架中,使用设计模式最大的问题在于如果在各个模式bean中能够注入Spring的bean,如果能够注入,那么将大大的扩展其使用方式。因为我们就可以真的实现通过传入的简单的几个参数,然后结合Spring注入的bean进行一定的处理后,以构造出我们所需要的某个bean。显然,这是lombok所无法实现的;
关于Builder模式,我们可以以前面奖励发放的SendPrizeRequest的构造为例进行讲解。在构造request对象的时候,必然是通过前台传如的某些参数来经过一定的处理,最后生成一个request对象。那么我们就可以使用Builder模式来构建一个SendPrizeRequest。
这里假设根据前台调用,我们能够获取到prizeId和userId,那么我们就可以创建一个如下的SendPrizeRequest:public class SendPrizeRequest { private final PrizeTypeEnum prizeType; private final int amount; private final String userId; public SendPrizeRequest(PrizeTypeEnum prizeType, int amount, String userId) { this.prizeType = prizeType; this.amount = amount; this.userId = userId; } @Component @Scope("prototype") public static class Builder { @Autowired PrizeService prizeService; private int prizeId; private String userId; public Builder prizeId(int prizeId) { this.prizeId = prizeId; return this; } public Builder userId(String userId) { this.userId = userId; return this; } public SendPrizeRequest build() { Prize prize = prizeService.findById(prizeId); return new SendPrizeRequest(prize.getPrizeType(), prize.getAmount(), userId); } } public PrizeTypeEnum getPrizeType() { return prizeType; } public int getAmount() { return amount; } public String getUserId() { return userId; } }
这里就是使用Spring维护一个Builder模式的示例,具体的 维护方式就是在Builder类上使用@Component和@Scope注解来标注该Builder类,这样我们就可以在Builder类中注入我们所需要的实例来进行一定的业务处理了。关于该模式,这里有几点需要说明:
1、在Builder类上必须使用@Scope注解来标注该实例为prototype类型,因为很明显,我们这里的Builder实例是有状态的,无法被多线程共享;
2、在Builder.build()方法中,我们可以通过传入的参数和注入的bean来进行一定的业务处理,从而得到构建一个SendPrizeRequest所需要的参数;
3、Builder类必须使用static修饰,因为在Java中,如果内部类不用static修饰,那么该类的实例必须依赖于外部类的一个实例,而我们这里本质上是希望通过内部类实例来构建外部类实例,也就是说内部类实例存在的时候,外部类实例是还不存在的,因而这里必须使用static修饰;
4、根据标准的Builder模式的使用方式,外部类的各个参数都必须使用final修饰,然后只需要为其声明getter方法即可。
上面我们展示了如何使用Spring的方式来声明一个Builder模式的类,那么我们该如何进行使用呢,如下是我们的一个使用示例:
@Service public class ApplicationService { @Autowired private PrizeSenderFactory prizeSenderFactory; @Autowired private ApplicationContext context; public void mockedClient() { SendPrizeRequest request = newPrizeSendRequestBuilder() .prizeId(1) .userId("u4352234") .build(); PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request); prizeSender.sendPrize(request); } public Builder newPrizeSendRequestBuilder() { return context.getBean(Builder.class); } }
上述代码中,我们主要要看一下newPrizeSendRequestBuilder()方法,在Spring中,如果一个类是多例类型,也即使用@Scope(“prototype”)进行了标注,那么每次获取该bean的时候就必须使用ApplicationContext.getBean()方法获取一个新的实例,至于具体的原因,读者可查阅相关文档。
我们这里就是通过一个单独的方法来创建一个Builder对象,然后通过流式来为其设置prizeId和userId等参数,最后通过build()方法构建得到了一个SendPrizeRequest实例,通过该实例来进行后续的奖励发放。 -
抽象类与java接口的区别
2007-09-01 20:07:00一个类可以实现任意多个接口,但它最多只能作为一个抽象类的字类(也就是说最多只能继承一个类). 2).一个抽象类可以含有若干个非抽象方法,它通常是模板方法模式的一个实例.而一个接口的所有方法都是抽象的,无论是否将... -
匿名内部类的几点说明
2012-11-07 23:58:241.匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。 2.匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。 3.匿名内部类不能定义构造器,... -
类图中常用的几个关系及表示法
2011-04-21 15:34:00UML中用得最多的就是类图,类图中常用的关系有以下几种: 1. 一般化关系:表示为类与类... 关联关系:表示类与类之间的联结,它使一个类知道另一个类的属性和方法。关联关系用表示。关联关系可以是单向的,也可以是 -
关于多线程共享资源的几个安全性问题
2019-09-30 00:54:56所谓同步就是指多个线程在同一个时间段内只能由一个线程进行操作,其他线程需要等待正在操作的线程完成操作之后才可以继续执行。 1 深入了解Thread类和Runnable接口 上一篇文章,我们介绍了关于多线程创建... -
hashmap扩容线程安全问题_关于多线程共享资源的几个安全性问题
2020-12-14 13:25:42多线程编程需要考虑最多的问题就是线程...一、深入了解Thread类和Runnable接口通过继承Thread类和实现Runnable接口都可以实现多线程的创建,那么两者有哪些联系和区别呢?01、Thread类的定义以下代码片段,摘自JDK... -
UML类图中常用的几个关系及表示法
2008-05-05 15:10:00UML中用得最多的就是类图,类图中常用的关系有以下几种: 1. 一般化关系:表示为类与类... 关联关系:表示类与类之间的联结,它使一个类知道另一个类的属性和方法。关联关系用表示。关联关系可以是单向的,也可以是 -
关于HashTable,HashMap和TreeMap的几点心得
2016-04-21 18:21:03Java为数据结构中的映射定义了一个接口java.util.Map,而HashMap Hashtable和TreeMap就是它的实现类。Map是将键映射到值的对象,一个映射不能包含重复的键;每个键最多只能映射一个一个值。 Hashmap 是一个最常用... -
设计模式实现(五)适配器模式
2020-07-05 22:23:35这样替换外部组件时,最多只要修改几个Adapter类就可以了,其他源代码都不会受到影响。 角色 Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。 Adapter(适配器类):... -
java读书笔记-《java设计模式》-第2章 - 接口型模式介绍
2013-11-12 23:28:401、一个类可以实现多个接口,但只能继承最多一个抽象类。 2、抽象类可以包含具体方法,接口的所有方法都是抽象的。 3、抽象类可以实现声明和使用字段;接口则不能,单可以创建静态的final常量。 4、抽象类中的... -
Java使用Proxy和CGLib实现动态代理
2016-01-07 21:30:56在java中对一个方法进行改造有几种方法可以实现,分别是最常用的继承(extends)、动态代理和装饰者模式。继承是最简单也是用的最多的方法,但是还是有一些场景不适用,这个时候就可能会用到动态代理。使用动态代理... -
Java语言入门教程(十六):Java语言中的接口
2009-07-22 17:10:00值得注意的是,Java中类与类的继承是单继承,也就是一个子类最多同时可以继承一个父类。那么让我们看下面的例子。 假设我们要开发一个游戏系统,而游戏系统中有三种飞行器:飞机、小鸟、蜘蛛侠。这三种飞行器都需要... -
hashmap为什么是2的倍数_HashMap的实现原理
2021-01-07 03:54:39参考链接:HashMap 的实现原理 - Java 集合学习指南 - 极客学院Wikiwiki.jikexueyuan.com上面的...主要有以下几个特性:HashMap中的key和value都允许为null,但最多只能拥有一个null的key。HashMap不保证顺序。Ha... -
求求大厂给个offer:list面试题
2020-08-21 15:03:55面试现场 面试官:“你简单自我介绍一下吧” 三歪:“我叫三歪,目前维护一个公众号叫做...三歪:“List在Java里边是一个接口,常见的实现类有ArrayList和LinkedList,在开发中用得最多的是ArrayList” 面试官:“你再 -
大话设计模式---设配器模式
2019-09-12 03:52:48适配器模式(Adapter):就是把一个类的接口变换成客户端所期待的另一种接口。 适配器模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样... -
abstract class 和 interface 的区别
2010-08-21 13:50:481. 一个类可以实现多个接口,但它最多只能作为一个抽象类的子类 2. 一个抽象类可以含有若干个非抽象方法,它通常是模板方法模式的一个实例。而一个接口的所有方法都是抽象的,无论是否将它的方法显示的声明为抽象 ... -
设计模式 — 适配器模式 (Adapter)
2019-07-31 21:38:34适配器模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)的类来透明的调用外部的组件,如此以来方便了不少,在替换外部组件时,最多只要修改几个Adapter类就可以了,而... -
适配器模式
2019-05-31 00:01:43Adapter模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替代外部组件时,最多只要修改几个Adapter类就可以了。 public class Current { ... -
入门学习Linux常用必会60个命令实例详解doc/txt
2011-06-09 00:08:45虚拟控制台的切换可以通过按下Alt键和一个功能键来实现,通常使用F1-F6 。 例如,用户登录后,按一下“Alt+ F2”键,用户就可以看到上面出现的“login:”提示符,说明用户看到了第二个虚拟控制台。然后只需按“Alt+... -
java集合框架----Map 源码分析
2020-02-21 20:38:46Map 简述 java.util.Map 接口表示键和值之间的映射对象。Map接口不是Collection接口的子类型。因此它的行为与其他集合类型略有不同。...Map 不能包含重复的键,每个键最多可以映射一个值。一些实现允许null键... -
java设计模式学习笔记第二章
2016-03-06 12:17:00一个类可以实现多个接口,但却只能继承最多一个抽象类。 2.抽象类可以包含具体方法;接口的所有方法都是抽象的。 3.抽象类可以声明和使用字段;接口则不能,但可以创建静态的final常量。 4.抽象类的方法... -
Java集合框架(十一):Map 源码分析
2020-05-06 11:05:591、Map 简述 java.util.Map 接口表示键和值之间的映射对象。Map接口不是Collection接口的子类型。因此它的行为与其他集合类型略有不同。...Map 不能包含重复的键,每个键最多可以映射一个值。一些实现允许nu... -
设计模式之适配器模式
2013-11-23 23:03:02也就是把一个类的接口变换成客户端所期待的另一种接口。 适配器模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替换外部组件时,最多...
-
平台级SAAS架构的基础:统一身份管理系统
-
基于电商业务的全链路数据中台落地方案(全渠道、全环节、全流程)
-
基于Qt的LibVLC开发教程
-
react+antd4,DatePicker组件只选择年月日,得到的时间戳不是当前日期的0点
-
基于MEH-PPV / ZnO纳米棒的混合聚合物太阳能电池的制备
-
轴承健康诊断的非线性降噪振动分析方法
-
使用 Linux 平台充当 Router 路由器
-
NFS 实现高可用(DRBD + heartbeat)
-
C语言零基础入门(详细讲解)
-
vue页面如何引入svg图标
-
四翼混沌吸引子的拓扑马蹄分析及电路实现
-
华为TE10轻型云视讯终端技术参数
-
架构师必备技能指南:SaaS(软件即服务)架构设计
-
cmd输出中文乱码问题
-
滞后过程PI控制器性能设计图解法
-
对比 Hashtable、HashMap、TreeMap 的区别联系以及适用场景
-
溶胶-凝胶法Er_2O_3薄膜的结构和光学特性
-
linux基础入门和项目实战部署系列课程
-
Windows系统管理
-
CBOEX交易所—牛年开跑,开启数字交易新局面!