一

{"type":"编程笔记"}


  • Home

  • Archives
  • Search

java inner class and jvm implements

Posted on 2017-08-07   |   In java

java中嵌套类型(nested type),也就是所谓的内部类(inner class),主要有四种:

  1. 静态内部类型,在类内部定义为static成员类型,如static class,静态内部类需要注意以下几点:
    1. 不管有没有static关键字,interface/annotation/enum都是静态类型;
    2. 静态内部类不能定义在任何非静态内部类中;
    3. 静态内部类的程序可以访问它所在的外部类的所有静态属性和方法,包括私有的静态属性和方法;
    4. 静态内部类其实就是顶层类,它不与任何对象关联;
    5. 静态内部类可以被声明为private的,但是interface里定义的方法仍然只能是public的。
  2. 非静态内部类,只能是class,注意:
    1. 一个非静态内部类的实例总是与外部类的实例outerClassInstance相关联;
    2. 非静态内部类的程序可以访问它所在的外部类的所有属性和方法,包括私有的方法;
    3. 不可以包含任何static属性,方法;
    4. java为非静态内部类设计了一些特殊语法,使用OuterClassName.this形式引用外部类的实例对象,其相关用法举例如下:
      1. OuterClassName.this.fieldName
      2. OuterClassName.this.anyMethod()
      3. OuterClassName.this.new InnerClassName()
      4. outerClassInstance.new InnerClassName()
    5. 内部类与外部类属性名相同时,访问外部类的实例属性,只能以OuterClassName.this.fieldName方式访问;
    6. 使用OuterClassName.super形式来访问外部类的超类。
  3. 局部类(local class),是定义在java代码块里的类,特点:
    1. interface/annotation/enum不能定义为局部类;
    2. 局部类可以访问代码块内可见范围内的所有final局部变量,java 8中变量可以不显式声明为final的,但实际是不能修改变量的引用;
    3. 局部类不能声明为private/protected/public/static,这些修饰符针对类成员,不能声明局部变量和局部类。
  4. 匿名类(annonymous class),是没有名称的局部类。
    1. 匿名类没有名称,所以在匿名类内是不能为它定义构造函数的,这是匿名类最大的限制;
    2. 可以使用初始化块来代替构造函数;
    3. 匿名类语法:
      1. new class-name ( [ argument-list ] ) { class-body }
      2. new interface-name () { class-body }

上面提到java为非静态内部类设计了一些特殊语法,应该尽量少用。

jvm中非静态内部类的实现说明

package com.example.test.javap;public class OuterClass {    class InnerClass {        private int var = 3;        private int test() {            return var;        }    }    public static void main(String[] args) {        OuterClass example = new OuterClass();        InnerClass innerClass = example.new InnerClass();        System.out.println(innerClass.test());    }}
Read more »

依赖反转原则与ioc/di的关系

Posted on 2017-07-29   |   In java

依赖反转原则 - Dependency Inversion Principle

wiki上对依赖反转原则说明如下:

In object-oriented design, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details.

该原则规定:

  1. 高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。
  2. 抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。

通常的抽象都来源于细节,来源于具体对象,通过对这些具体对象进行分析思考,从而形成高层的抽象对象或者是接口,所以直观的来看一般都是抽象依赖于细节,而DIP原则正好是将之倒置,要求细节依赖于抽象。

上图高层模块1中对象A依赖于具体对象B,图中模块1重构后,对象A依赖于低层模块中对象B的抽象接口InferfaceB,而在低层模块2中的对象B实现了此接口,一般通过IoC/DI完成对象调用,从而达到细节依赖抽象,而不是抽象依赖细节,这就是依赖反转。

面向对象编程中,最根本的一个原则就是分离变化与不变化的部分,面向对象的三大特性(封装、继承和多态),六大原则(SOLID),若干设计模式,本质都是体现这个原则,即分离对象中变化和不变化的部分,分离模块中变化与不变化的部分,依赖反转原则中抽象的部分就是相对不变的部分,变化的部分即具体的细节的低层对象。

控制反转 - Inversion of Control

wiki上对控制反转的说明如下:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的实现方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫依赖查找(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

in software engineering, inversion of control (IoC) is a design principle in which custom-written portions of a computer program receive the flow of control from a generic framework. a software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code.

inversion of control is used to increase modularity of the program and make it extensible, and has applications in object-oriented programming and other programming paradigms. the term was popularized by Robert C. Martin and Martin Fowler.

the term is related to, but different from, the dependency inversion principle, which concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions. the general concept is also related to event-driven programming in that it is often implemented using ioc, so that the custom code is commonly only concerned with handling of events, whereas the event loop and dispatch of events/messages is handled by the framework or the runtime environment.

依赖注入 - Dependency Injection

一般说到控制反转,都会和依赖注入一起提到,从上面的定义也可以知道,IoC是一个设计原则,而依赖注入是它的实现方式之一,依赖注入这个概念的提出可以参考 Martin Fowler 的这篇文章,对应的中文版本。

Read more »

tomcat startup blocked because stackoverflow error

Posted on 2017-02-26   |   In java

spring项目在tomcat中启动时,会随机的卡死,tomcat启动失败,关闭之后重启有时就会正常启动,失败时的日志输出到如下位置时停下来,没有异常输出到控制台。

2017-02-26 17:40:05 [ RMI TCP Connection(2)-127.0.0.1:4882 ] - [ INFO ] org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker.postProcessAfterInitialization(AbstractApplicationContext.java:1350) Bean 'dataSource' of type [class com.example.DataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

debug时发现一直卡在spring容器AbstractAutowireCapableBeanFactory的doCreateBean和populateBean方法中:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory        implements AutowireCapableBeanFactory {    // ... other codes    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {        // ... other codes        // Initialize the bean instance.        Object exposedObject = bean;        try {            // 调试时一直在这里不断的递归调用            populateBean(beanName, mbd, instanceWrapper);            if (exposedObject != null) {                exposedObject = initializeBean(beanName, exposedObject, mbd);            }        }        catch (Throwable ex) { // spring 在此捕获了所有Exception和Error,并重新包装了一个运行时异常 BeanCreationException            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {                throw (BeanCreationException) ex;            }            else {                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);            }        }        // ... other codes    }    // ... other codes }

碰到这个问题,第一反应是与数据库连接有关系,而且日志输出到了dataSource相关的位置停下来的,然后debug时一直不断在尝试在创建mybatis的sqlSessionFactory这个bean以及相关的一些Dao,因为多数情况下还是能正常启动tomcat的,所以数据库配置是没有问题,而且在windows开发机器上也没有发生这样的情况,只有在测试服务器linux环境和本地Mac系统中偶尔发生。

解决问题想到的相关工具和方法

打开日志DEBUG级别

因为出错时的日志一开始是INFO级别的,所以碰到问题后就设置为DEBUG级别,希望看到更详细的信息,但是与INFO级别没什么大的区别,卡死的位置也是一样的,因此日志并没有提供更多有价值的信息。

检查tomcat的相关日志文件

主要检查了catalina.out和localhost.yyyy-MM-dd.log这2个日志文件,里面也没有任何异常堆栈信息。

Read more »

jvm instructions listings

Posted on 2017-01-18   |   In java

Java Virtual Machine Online Instruction Reference对每个虚拟机指令都有更详细的说明,并配有示例,非常的易于理解,每个指令可以参考这份文档进行学习。

下面按虚拟机指令的作用类型分成以下几大组,每个指令上的链接指向官网说明文档。

Data Operations

The Stack

Pushing constants onto the stack

opcode Description
bipush Push a signed byte.
sipush Push a signed word.
ldc Push a single word constant.
ldc_w Push a single word constant. (16-bit ref in constant pool)
ldc2_w Push a double word constant.
aconst_null Push the null object.
iconst_m1 Push integer -1.
iconst_i Integers i = 0..5.
lconst_l Longs l = 0..1.
fconst_f Floats f = 0.0..2.0.
dconst_d Doubles d = 0.0..1.0.

Stack Manipulation

opcode Description
nop Do nothing.
pop Pop the top word.
pop2 Pop the top two words.
dup Duplicate the top word to place 2.
dup2 Duplicate the top two words.
dup_x1 Duplicate the top word to place 3.
dup2_x1 Duplicate the top two words to places 4 and 5.
dup_x2 Duplicate the top word to place 4.
dup2_x2 Duplicate the top two words to places 5 and 6.
swap Swap the top two words.

Local Variables

Push local

opcode Description
aload Load object from local variable n
aload_n Load object from local variable n : n = 0..3
dload Load double from local variable n
dload_n Load double from local variable n : n = 0..3
fload Load float from local variable n
fload_n Load float from local variable n : n = 0..3
iload Load integer from local variable n
iload_n Load integer from local variable n : n = 0..3
lload Load long from local variable n
lload_n Load long from local variable n : n = 0..3

Pop stack into local var

opcode Description
astore store object in local variable n
astore_n store object in local variable n : n = 0..3
dstore store double in local variable n
dstore_n store double in local variable n : n = 0..3
fstore store float in local variable n
fstore_n store float in local variable n : n = 0..3
istore store integer in local variable n
istore_n store integer in local variable n : n = 0..3
lstore store long in local variable n
lstore_n store long in local variable n : n = 0..3
Read more »

the lifetime of a class

Posted on 2016-12-26   |   In java

The previous chapter described in detail the format of the Java class file, the standard binary form for representing Java types. This chapter looks at what happens when binary type data is imported into a Java Virtual Machine. The chapter follows the lifetime of a type (class or interface) from the type's initial entrance into the virtual machine to its ultimate exit. It discusses the processes of loading, linking, and initialization that occur at the beginning of a class's lifetime; the processes of object instantiation, garbage collection, and finalization that can occur in the prime of a class's lifetime; and the finalization and unloading of types that can occur at the end of a class's lifetime.

Class Loading, Linking, and Initialization

The Java Virtual Machine makes types available to the running program through a process of loading, linking, and initialization. Loading is the process of bringing a binary form for a type into the Java Virtual Machine. Linking is the process of incorporating the binary type data into the runtime state of the virtual machine. Linking is divided into three sub-steps: verification, preparation, and resolution. Verification ensures the type is properly formed and fit for use by the Java Virtual Machine. Preparation involves allocating memory needed by the type, such as memory for any class variables. Resolution is the process of transforming symbolic references in the constant pool into direct references. Implementations may delay the resolution step until each symbolic reference is actually used by the running program. After verification, preparation, and (optionally) resolution are completed, the type is ready for initialization. During initialization, the class variables are given their proper initial values. See Figure 7-1 for a graphical depiction of this process.

As you can see from Figure 7-1, the processes of (1) loading, (2) linking, and (3) initialization must take place in that order. The only exception to this required ordering is the third phase of linking, resolution, which may optionally take place after initialization.

The Java Virtual Machine specification gives implementations flexibility in the timing of class and interface loading and linking, but strictly defines the timing of initialization. All implementations must initialize each class and interface on its first active use. An active use of a class is:

  1. The invocation of a constructor on a new instance of the class
  2. The creation of an array that has the class as its an element type
  3. The invocation of a method declared by the class (not inherited from a superclass)
  4. The use or assignment of a field declared by the class (not inherited from a superclass or superinterface), except for fields that are both static and final, and are initialized by a compile-time constant expression

An active use of an interface is:

  1. The use or assignment of a field declared by the interface (not inherited from a superinterface), except for fields that are initialized by a compile-time constant expression

All other uses of a type besides the five listed above are passive uses of the type. Several examples illustrating the difference between active and passive uses are given later in this chapter.

Aside from its own initial active use, there is one other situation that will cause the initialization of a class: the initial active use of one of its subclasses. Initialization of a class requires prior initialization of all its superclasses.

The same is not true of interfaces, however. An interface is initialized only because a non-constant field declared by the interface is used, never because a subinterface or class that implements the interface needs to be initialized. Thus, initialization of a class requires prior initialization of all its superclasses, but not its superinterfaces. Initialization of an interface does not require initialization of its superinterfaces.

The "initialize on first active use" rule drives the mechanism that loads, links, and initializes classes. On its first active use, a type must be initialized. Before it can be initialized, however, it must be linked. And before it can be linked, it must be loaded. At their option, implementations may load and link types early. They need not wait until the type's first active use to load and link the type. If a type hasn't been loaded and linked before its first active use, however, it must be loaded and linked at that time, so that it can be initialized.

Loading

The loading process consists of three basic activities. To load a type, the Java Virtual Machine must:

  1. produce a stream of binary data that represents the type
  2. parse the stream of binary data into internal data structures in the method area
  3. create an instance of class java.lang.Class that represents the type

The stream of binary data may adhere to the Java class file format, but could alternatively follow some other format. As mentioned in previous chapters, all Java Virtual Machine implementations must recognize the Java class file format, but individual implementations may also recognize other binary formats.

The Java Virtual Machine specification does not say how the binary data for a type must be produced. Some potential ways to produce binary data for a type are:

  1. load a Java class file from the local file system
  2. download a Java class file across a network
  3. extract a Java class file from a ZIP, JAR, CAB, or other archive file
  4. extract a Java class file from a proprietary database
  5. compile a Java source file on the fly into the class file format
  6. compute the class file data for a type on the fly
  7. any of the above, but using a binary file format other than the Java class file

Given the binary data for a type, the Java Virtual Machine must process that data to a great enough extent that it can create an instance of class java.lang.Class. The virtual machine must parse the binary data into implementation-dependent internal data structures. (See Chapter 5, "The Java Virtual Machine," for a discussion of potential internal data structures for storing class data.) The Class instance, the end product of the loading step, serves as an interface between the program and the internal data structures. To access information about a type that is stored in the internal data structures, the program invokes methods on the Class instance for that type.

As described in previous chapters, types are loaded either through the primordial class loader or through class loader objects. The primordial class loader, a part of the virtual machine implementation, loads types (including the classes and interfaces of the Java API) in an implementation-dependent way. Class loader objects, instances of subclasses of java.lang.ClassLoader, load classes in custom ways. The inner workings of class loader objects are described in more detail later in Chapter 8, "The Linking Model."

Class loaders (primordial or object) need not wait until a type's first active use before they load the type. Class loaders are allowed to cache binary representations of types, load types early in anticipation of eventual use, or load types together in related groups. If a class loader encounters a problem during early loading, however, it must report that problem (by throwing a subclass of LinkageError) only upon the type's first active use. In other words, if a class loader encounters a missing or malformed class file during early loading, it must wait to report that error until the class's first active use by the program. If the class is never actively used by the program, the class loader will never report the error.

Read more »
1…131415…99
yuweijun

yuweijun

492 posts
12 categories
RSS
GitHub Twitter
© 2021 yuweijun
Powered by Hexo
Theme - NexT.Mist.KISS