HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Hibernate / How Hibernate Second Level Cache Works?

How Hibernate Second Level Cache Works?

Caching is facility provided by ORM frameworks which help users to get fast running web application, while help framework itself to reduce number of queries made to database in a single transaction. Hibernate also provide this caching functionality, in two layers.

  • Fist level cache: This is enabled by default and works in session scope. Read more about hibernate first level cache.
  • Second level cache: This is apart from first level cache which is available to be used globally in session factory scope.

Above statement means, second level cache is created in session factory scope and is available to be used in all sessions which are created using that particular session factory.
It also means that once session factory is closed, all cache associated with it die and cache manager also closed down.
Further, It also means that if you have two instances of session factory (normally no application does that), you will have two cache managers in your application and while accessing cache stored in physical store, you might get unpredictable results like cache-miss.

hibernate first and second level cache_example
Hibernate first and second level cache

In this tutorial, I am giving concepts around hibernate second level cache and give example using code snippets.

How second level cache works

Lets write all the facts point by point:

  1. Whenever hibernate session try to load an entity, the very first place it look for cached copy of entity in first level cache (associated with particular hibernate session).
  2. If cached copy of entity is present in first level cache, it is returned as result of load method.
  3. If there is no cached entity in first level cache, then second level cache is looked up for cached entity.
  4. If second level cache has cached entity, it is returned as result of load method. But, before returning the entity, it is stored in first level cache also so that next invocation to load method for entity will return the entity from first level cache itself, and there will not be need to go to second level cache again.
  5. If entity is not found in first level cache and second level cache also, then database query is executed and entity is stored in both cache levels, before returning as response of load() method.
  6. Second level cache validate itself for modified entities, if modification has been done through hibernate session APIs.
  7. If some user or process make changes directly in database, the there is no way that second level cache update itself until “timeToLiveSeconds” duration has passed for that cache region. In this case, it is good idea to invalidate whole cache and let hibernate build its cache once again. You can use below code snippet to invalidate whole hibernate second level cache.
/**
 * Evicts all second level cache hibernate entites. This is generally only
 * needed when an external application modifies the databaase.
 */
public void evict2ndLevelCache() {
    try {
        Map<String, ClassMetadata> classesMetadata = sessionFactory.getAllClassMetadata();
        for (String entityName : classesMetadata.keySet()) {
            logger.info("Evicting Entity from 2nd level cache: " + entityName);
            sessionFactory.evictEntity(entityName);
        }
    } catch (Exception e) {
        logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);
    }
}

To understand more using examples, I wrote an application for testing in which I configured EhCache as 2nd level cache. Lets see various scenarios:

a) Entity is fetched very first time

DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 0

Output: 1 0

Explanation: Entity is not present in either 1st or 2nd level cache so, it is fetched from database.

b) Entity is fetched second time

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 0

Output: 1 0

Explanation: Entity is present in first level cache so, it is fetched from there. No need to go to second level cache.

c) Entity is evicted from first level cache and fetched again

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//Evict from first level cache
session.evict(department);
			
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 1

Output: 1 1

Explanation: First time entity is fetched from database. Which cause it store in 1st and 2nd level cache. Second load call fetched from first level cache. Then we evicted entity from 1st level cache. So third load() call goes to second level cache and getSecondLevelCacheHitCount() returns 1.

d) Access second level cache from another session

//Entity is fecthed very first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//Evict from first level cache
session.evict(department);
			
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 2

Output: 1 2

Explanation: When another session created from same session factory try to get entity, it is successfully looked up in second level cache and no database call is made.

So now we are clear on how second level cache is used by hibernate.

Download sourcecode

Drop me a comment if any query or suggestion.

Happy Learning !!

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.
TwitterFacebookLinkedInRedditPocket

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. Praful Anand

    January 14, 2020

    why case a and case b have equal output 1 for getEntityFetchCount() method? while in case an entity is fetched from the database and in case b entity is fetched from first level cache still getEntityFetchCount() method has the same output 1. Please clarify for this one

  2. Khandave Chetan Mhatardeo

    February 20, 2019

    When I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) for pojo class then there is problem occours.
    when I evict entity from session then it get removed from 1st level cache it’s fine but when I again fetch it then query get fire. I check that entity is present in 2nd level cache but still query get fire.
    If I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) then it works fine.
    please help me to understand it

  3. Vijay

    December 27, 2017

    Hi I have one question like
    why hibernate is not given any implementation for second level cache.
    As we have so many third party providers EHCache, OSCache, SwarmCache, JBoss Cache 1.x
    Is there any specific reason for this.
    Can you please help me out understanding this

    Thanks
    Vijay

  4. Sachin Kumar

    October 20, 2016

    Good post.

    One clarification, does the hibernate second level cache gets updated when we fire HQL update queries ?

  5. Sachin Kumar

    October 18, 2016

    Very useful.

    One clarification, when we there is an entity in second level cache ( say for ex: Table1 ) and when I fire HQL like
    HibernateSEssion.query(“update Table1 set col1= value ….”). Will this update the object in second level cache ?

    • Lokesh Gupta

      October 21, 2016

      Good question. I believe that second level cache will not be updated. Van you please try and share your findings.

  6. Ali Kemal

    September 26, 2016

    thanks a lot…

  7. Vishal Kumawat

    August 17, 2016

    is Second level cache Enabled by default in Hibernate ?

    • Lokesh Gupta

      August 17, 2016

      No.

    • Kiran Kumar U

      July 27, 2018

      No. you need to add the below configuration in hibernate.cfg.xml
      true

  8. Binh Thanh Nguyen

    July 6, 2016

    Thanks, nice examples.

  9. Ashwinee

    November 20, 2015

    great

  10. Geeta

    May 18, 2015

    Nice and very simple to understand articles. Do you have any article explaining Hibernate architecture? Also do you have any article explaining of hibernate does fetching of many records say hundred thousands of records with loadAll() using threads?

  11. RL

    April 15, 2015

    when or how does the cacheget invalidated?
    example : I retrieve an emp object from the database with max salary
    and doing some work on the entity. while there is a batch tat onboards new employees and adds a new max to the table.

    if i am in the same session, hibernate sends the result from the fiirst or second level cache.
    so what is the indicator here ? how does it know to refresh apart from time to live attr?

    • Lokesh Gupta

      April 15, 2015

      If update happens outside hibernate (e.g. direct insert queries in database) then hibernate will not be able to detect if such change happen. So in this case, there should be an option in application admin panel which can invalidate all cache/selected caches.

      Refer : https://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/Cache.html

  12. Narasimhulu

    November 10, 2014

    I am struggling for 2ndlevel cache , anyone explain 2nd level cache and also
    explain one realworld scenaria for 2nd level cache please….

    • Lokesh Gupta

      November 11, 2014

      Any application, which is going to be used by a large group of users, is supposed to have caching enabled. Applications usually execute a lot of similar data to different type of users. If you fetch this data from database every time from database, then database will become heavily loaded and busy. To share the load, second lvl caching comes into picture. It stores data inform of indexes mostly into physical filesystem very near to server itself. So data retrieval time comes down drastically and results into higher performance.

    • Kishore Anand

      August 10, 2019

      Hi Narasimhulu,

      I guess, In real world it will be useful in multi-threaded batch applications. Were multiple threads access same table. So if one thread as fetched data from the table, other threads using different sessions need not make db calls but instead fetch from ehcache.

      Lokesh correct me if I am wrong. I can try it and share an example.

      Thanks.

  13. Vikas Gandahm

    August 27, 2014

    I have set up 2nd level cache in our application.For the first call it fetches from the database and for the 2nd call it gets from cache(found out from postgres logs).The issue is if the object has boolean attributes these attributes has null when fetched from cache though there value is true/false.Does any one faced this issue please let me know. Strucked with this for almost 4 days and did not find the solution

    • Vikas Gandahm

      August 28, 2014

      I found the issue.We have defined custom User Types for these boolean attributes.These custom user types has to implement dissemble and assemble functions which are used using caching.We were returning null for these two functions which were causing issue.When i modified it to return the values it takes as in parameters it started working normally.

      • Lokesh Gupta

        August 29, 2014

        Thanks for sharing the solution Vikas.

  14. swekha

    August 26, 2014

    how to enable second level cache?

    • Lokesh Gupta

      August 26, 2014

      You need to configure it. Look at examples given for EhCache and OSCache configuration.

  15. Yogesh Prajapati

    August 5, 2014

    where first level and second level cache stores objects, in memory or physical storage?

    • Lokesh Gupta

      August 5, 2014

      First level cache is always stored in memory. Second level cache depends on your implementation choice (configuration) of cache.

  16. Amit

    July 17, 2014

    Really neat and short article.

    Does hibernate refers to 2-level cache for Session.get(Entity.class, id) method?

    • Lokesh Gupta

      July 17, 2014

      It will first check in first level cache, if not there then it will check in second level cache.

  17. Sumit Chakraborty

    May 29, 2014

    Shouldn’t this be session.get instead of session.load? The latter returns a proxy object with id attached and does not hit the database whereas the former (i.e. get) always hits the database if not found in cache.

    Please correct me if wrong.

    • Lokesh Gupta

      May 30, 2014

      session.load() return the proxy object but if row doesn’t exist it will throw ObjectNotFoundException whereas session.get() return null. For above example, both will produce the same result.

  18. mahendra

    May 25, 2014

    Hi Lokesh, I want create a new session factory based on some data extracted from database at runtime and close current sessionfactory. What sholud I do in this case? Please correct me if I am wrong.

    • Lokesh Gupta

      May 25, 2014

      It’s interesting question. First thing first.. why would someone do this? As far as implementation is concerned, nothing is impossible.

  19. Anshuman Dwivedi

    May 8, 2014

    Hi Lokesh,
    I have configured ehcache as you have depicted in your “Configuring ehcache post”. But In my cache it fails to load ehcache.xml . This is why by default it is picking “ehcache-1.2.3.jar!/ehcache-failsafe.xml”.
    Please suggest where should I keep ehcache.xml to get it loaded and considered.

    • Lokesh Gupta

      May 8, 2014

      Place it anywhere in classpath i.e. “/WEB-INF/classes” folder. Or configure here: <property name=”net.sf.ehcache.configurationResourceName”>/ehcache.xml</property>

      • Anshuman

        May 9, 2014

        Hi Lokesh,
        I have put this line in hibernate.cfg.xml “/ehcache.xml”. Accordingly also placed ehcache.xml at the same level as that of hibertnate.cfg.xml. But again its not picking this file and going to default file. In my case I am running program from eclipse directly so there is no place for “/WEB-INF/classes” folder. Please suggest how can I get ehcache.xml file noticed.

        • Lokesh Gupta

          May 9, 2014

          In your src folder. If still not picking up, then paste the hardcoded full path [e.g. c:/temp/ehcache.xml].

        • Anshuman

          May 9, 2014

          Thanks Lokesh,
          I got it configured and running. Now its picking my ehcahce.xml.
          Please suggest any way by which I can clear/flush second level cache. Additionally where this second level cache is created on fileSystem ?

          • Lokesh Gupta

            May 9, 2014

            Use any of
            sf.getCache().evictEntityRegions()
            sf.getCache().evictCollectionRegions()
            sf.getCache().evictDefaultQueryRegion()
            sf.getCache().evictQueryRegions()

  20. raun

    March 29, 2014

    Thanks Lokesh for sharing it.

    You mentioned first level cache is available by default. What about second level cache. Do we need to have some configuration for the 2nd level cache.
    If yes, how we do it? Can you please elaborate?

    • Lokesh Gupta

      March 29, 2014

      Refer here: https://howtodoinjava.com/hibernate/hibernate-ehcache-configuration-tutorial/

  21. venkata

    March 16, 2014

    Hi Lokesh,

    which scenario we can use first level cache since it belongs to session and will not available in other methods.

    • Lokesh Gupta

      March 17, 2014

      Hibernate uses first level cache mainly to reduce the number of SQL queries it needs to generate within a given transaction. For example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE statement at the end of the transaction, containing all the modifications.

  22. venkata

    March 15, 2014

    Hi Loken,

    Your tutorials are really useful for understanding each concept very clearly. In one of the interview they asked me how to refresh web page content that database changes every 30 minutes automatically using any caching? if possible could you please explain me with examples?

    • Lokesh Gupta

      March 15, 2014

      Use anyone from below:

      1) https://en.wikipedia.org/wiki/Meta_refresh
      2) https://www.ibm.com/developerworks/web/library/wa-reverseajax4/?ca=drs-
      3) https://github.com/Atmosphere/atmosphere
      4) http://www.icesoft.org/wiki/display/ICE/Easy+Ajax+Push

      • venkata

        March 15, 2014

        Thanks for your reply but they were asked me using hibernate caching mechanism that is only new changes during that 30 minutes period need to get from database and existing results should get from hibernate cache and same needs to display to the user.

        • Lokesh Gupta

          March 15, 2014

          Then all you need to display the page from server side cache. Ans let the cache re-build or refresh at 30 minutes period.

          • venkata

            March 15, 2014

            Yes, we need to do use server side cache. if possible could you please provide me sample code how can we set time interval at server side cache.

  23. VasuDev

    February 3, 2014

    Hey Lokesh,
    thanx for the early reply….Can u suugest me one: I am implementing rest Webservices, Now i need to implement Caching for the same, I have gone through so many Articles in the net regarding the Http etcc, but i am not able to cache my rest WS, can u put some light on the same…….

    • Lokesh Gupta

      February 3, 2014

      I will suggest this: https://docs.jboss.org/resteasy/docs/1.2.GA/userguide/html/Cache_NoCache_CacheControl.html#server_cache

  24. VasuDev

    February 3, 2014

    Hi Lokesh…..
    I have a doubt:
    My scenario: i am implementing hibernate second level caching:
    I have totally different application to alter the Database, i never use my HIbernate application for insert or update, i just use for Retrieving the data. suppose i have retrieved a data and i alter the database with different application, can u tell me whether the second level cache still works for the same database which i have altered using diff application…..

    • Lokesh Gupta

      February 3, 2014

      Hibernate second level cache works at “SessionFactory scope/level”. So, till the time you have common SessionFactory for different sessions in your application you are good. But, in your case you have a completely different application with (assuming) different SessionFactory altogether, So in your case, second level cache WILL NOT WORK with exact behavior as in single application.

      Please do not misunderstood me here. Although the caching will happen at both applications but it will be independent at both ends regardless the changes done by any of application.

  25. Venkatesh

    January 30, 2014

    Hi Lokesh Gupta, Nice tutorials your posted i Have Implemented Second level Cache Mechanism.session is not loaded from the Second level cache if your remove the department.getName() its not hitting Second level Cache Mechanism could you tel me what is reason

    • Lokesh Gupta

      January 30, 2014

      Can you please post the code you are playing with.

  26. Dibyendu

    January 23, 2014

    This is simply great.You have explained so nicely and cleanly.
    Thank you so much.

  27. rajinder

    January 7, 2014

    Can u please explain about concurrency strategies used to configure second level cache at class level like transactional, read-write etc . i mean which strategy to be used when?

    • Lokesh Gupta

      January 10, 2014

      OK

  28. Suri

    November 26, 2013

    Hi Mr Gupta,

    Its really great and easily understandable….
    I ll keep communicating with you learn more….

    Thank you very much

  29. Артур Хуснутдинов

    November 8, 2013

    Thank you very much.

  30. han

    October 31, 2013

    HI Lokesh
    I followed your step to print out below two lines
    System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());
    System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());

    above four conditions you mentioned, it always shows 0 0
    could you help me to figure it out?

    Thank you

    • Lokesh Gupta

      October 31, 2013

      Try setting following in hibernate configuration properties

      hibernate.generate_statistics————————– true
      hibernate.cache.use_structured_entrie————– true

      • han

        October 31, 2013

        Hi, Lokesh,
        Thank you for replying
        I put those settings in xml file,
        a,b works well, but c shows 2 0 not 1 1
        do you know why it is ?
        Thank you

        • Lokesh Gupta

          October 31, 2013

          It must me 0 2…………. not 2 0.
          Reason is second level cache is already created. So DB hits are 0. Delete the second level cache from file system and you will get desired result.

          • Anshuman Dwivedi

            May 8, 2014

            Hi Lokesh,
            Can you specify where this second level cache is created on file system ? and Is there any way to clear/flush this cache ?

            • Lokesh Gupta

              May 8, 2014

              Use the configuration like this:

              <ehcache>
              <diskStore path=”java.io.tmpdir”/>
              <defaultCache
              maxEntriesLocalHeap=”10000″
              eternal=”false”
              timeToIdleSeconds=”120″
              timeToLiveSeconds=”120″
              maxEntriesLocalDisk=”10000000″
              diskExpiryThreadIntervalSeconds=”120″
              memoryStoreEvictionPolicy=”LRU”
              <persistence strategy=”localTempSwap”/>
              />
              </ehcache>

              Read this section from official documentation: http://www.ehcache.org/documentation/2.8/get-started/storage-options.html

  31. Swati

    October 24, 2013

    Very very helping. Thanks. I need something which can differentiate b/w SOAP and REST web services . Can you please help me ?

    • Lokesh Gupta

      October 24, 2013

      https://stackoverflow.com/questions/2131965/main-differences-between-soap-and-restful-web-services-in-java

  32. hoangedward

    October 9, 2013

    Thanks for your very nice post.

    Could you answer some questions from me?
    Can I disable the 2nd cache level? I know the advantages of caching mechanism but I think there are some disadvantages of it, so could tell me more about this?

    Thank you a lot, I’m waiting for your response.

    • Lokesh Gupta

      October 9, 2013

      1) Want to disable second level cache? Don’t configure it. Simple and most obvious.
      2) Yes, caching is boon to your application but it introduces certain overhead also. Everytime, you update something or delete something or even create create something, you need to invalidate certain cache blocks and re-build them so they have latest data. This step becomes more complex when cache is distributed. But believe me, advantages outweigh any such overhead.

  33. sridhar

    September 30, 2013

    Is cache applicable for only load methods or it is also for save/update methods.
    Mean when we save an entity will it be stored in cache before saving in DB ?

    • Lokesh Gupta

      September 30, 2013

      NO. “Cache is only for selecting the data”. When you update something, if method return the updated entity, then in back-end it automatically fires a SELECT query which invalidate/update the first/second level caches. Otherwise if its only update operation, you will have to fetch the updated entity once again.

      • venkata

        March 16, 2014

        Hi Lokesh,
        can we use load method to fetch all the records at a time instead of one record .

        • Lokesh Gupta

          March 17, 2014

          I believe NO. Load is used to load one entity (it’s proxy) by given identifier. For loading all records, use named queries.

  34. Prakash

    September 24, 2013

    Nice Post.. After long search in Google on this topic…Thanks once again

  35. rangareddyavulay

    September 22, 2013

    Hi Gupta, Nice tutorials your posted. I want Second Level Cache Implementation by using Hiberante4 with Maven. I tried many ways. There is proper resource to implement. Please Can you provide one example by using Hibernate4.

    • Lokesh Gupta

      September 22, 2013

      I have posted one such implementation using OSCache. It is using Hibernate 3, but it will definitely help you to achieve your goal.

      https://howtodoinjava.com/hibernate/hibernate-oscache-configuration-example-tutorial/

  36. Sravan Kumar

    July 4, 2013

    Ih,
    If i would like to use NO-SQL DB as hibernate second level cache, what i have to do..?
    what are the classes i need to customise.

    • Lokesh Gupta

      July 15, 2013

      You can start from here:

  37. subbareddy

    July 3, 2013

    hi,
    I need webservices tutorials please share that……

    • Lokesh Gupta

      July 3, 2013

      I have written lots of RESTful WS tutorials. So far didn’t got time to explore SOAP WS. May be in future.

      https://howtodoinjava.com/restful-web-service/

      • subbareddy

        July 3, 2013

        thnks

  38. subbareddy

    July 3, 2013

    nice post it is very useful to all

  39. Shubhi

    July 2, 2013

    Great post. Thanks for sharing the concepts.

Comments are closed on this article!

Search Tutorials

Hibernate Tutorial

  • Hibernate – Introduction
  • Hibernate – Hello World
  • Hibernate – Get/Fetch
  • Hibernate – Persist
  • Hibernate – Merge & Refresh
  • Hibernate – Get Entity Reference
  • Hibernate – BLOB
  • Hibernate – Save Update
  • Hibernate – Persistence LifeCycle
  • Hibernate – SessionFactory
  • Hibernate – Entities Equality
  • Hibernate – Cascade Types
  • Hibernate – Lazy Loading
  • Hibernate – Criteria Queries
  • Hibernate – HQL
  • Hibernate – Named Query
  • Hibernate – Mappings
  • Hibernate – First Level Cache
  • Hibernate – Second Level Cache
  • Hibernate – EhCache Configuration
  • Hibernate – OSCache Configuration
  • Hibernate – C3P0 Connection Pool
  • Hibernate – In memory Database
  • Hibernate – Bean Validation
  • Hibernate – Validator CDI
  • UnexpectedTypeException

Hibernate Annotations

  • Hibernate – JPA 2 Annotations
  • Annotations Vs Mappings
  • Hibernate – @Immutable
  • Hibernate – @NaturalId
  • Hibernate – @OneToMany
  • Hibernate – @ManyToMany
  • Hibernate – @OneToOne

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Sealed Classes and Interfaces