찾다
Javajava지도 시간Java 주석의 정의 및 사용 소개(코드 예제)

Java 주석의 정의 및 사용 소개(코드 예제)

Feb 21, 2019 pm 02:41 PM
javaspring주석

이 글은 Java 주석(코드 예제)의 정의와 사용에 대해 설명합니다. 필요한 참고가 될 수 있습니다.

Java 주석은 실제 프로젝트에서 많이 사용되며, 특히 Spring을 사용한 후에는 더욱 그렇습니다.

이 글에서는 Java Annotation의 구문과 Spring에서 Annotation을 사용하는 예를 소개합니다.

주석의 구문

주석의 예

Junit의 @Test 주석을 예로 들어보세요

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    long timeout() default 0L;
}

@Test 주석에 @Target()가 있는 것을 볼 수 있습니다. > 및 @Retention()두 개의 주석.
주석에 주석을 추가하는 이러한 종류의 주석을 메타 주석이라고 합니다.
데이터를 선언하는 데이터, 즉 메타데이터와 같은 의미입니다. @Test注解上有@Target()@Retention()两个注解。
这种注解了注解的注解,称之为元注解
跟声明了数据的数据,称为元数据是一种意思。

之后的注解的格式是

修饰符 @interface 注解名 {   
    注解元素的声明1 
    注解元素的声明2   
}

注解的元素声明有两种形式

type elementName();
type elementName() default value;  // 带默认值

常见的元注解

@Target注解

@Target注解用于限制注解能在哪些项上应用,没有加@Target的注解可以应用于任何项上。

java.lang.annotation.ElementType类中可以看到所有@Target接受的项

  • TYPE 在【类、接口、注解】上使用

  • FIELD 在【字段、枚举常量】上使用

  • METHOD 在【方法】上使用

  • PARAMETER 在【参数】上使用

  • CONSTRUCTOR 在【构造器】上使用

  • LOCAL_VARIABLE 在【局部变量】上使用

  • ANNOTATION_TYPE 在【注解】上使用

  • PACKAGE 在【包】上使用

  • TYPE_PARAMETER 在【类型参数】上使用 Java 1.8 引入

  • TYPE_USE 在【任何声明类型的地方】上使用 Java 1.8 引入

@Test注解只允许在方法上使用。

@Target(ElementType.METHOD)
public @interface Test { ... }

如果要支持多项,则传入多个值。

@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation { ... }

此外元注解也是注解,也符合注解的语法,如@Target注解。
@Target(ElementType.ANNOTATION_TYPE)表明@Target注解只能使用在注解上。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

@Retention注解

@Retention指定注解应该保留多长时间,默认是RetentionPolicy.CLASS
java.lang.annotation.RetentionPolicy可看到所有的项

  • SOURCE 不包含在类文件中

  • CLASS 包含在类文件中,不载入虚拟机

  • RUNTIME  包含在类文件中,由虚拟机载入,可以用反射API获取

@Test注解会载入到虚拟机,可以通过代码获取

@Retention(RetentionPolicy.RUNTIME)
public @interface Test { ... }

@Documented注解

主要用于归档工具识别。被注解的元素能被Javadoc或类似的工具文档化。

@Inherited注解

添加了@Inherited注解的注解,所注解的类的子类也将拥有这个注解

注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation { ... }

父类

@MyAnnotation 
class Parent { ... }

子类Child会把加在Parent上的@MyAnnotation继承下来

class Child extends Parent { ... }

@Repeatable注解

Java 1.8 引入的注解,标识注解是可重复使用的。

注解1

public @interface MyAnnotations {   
    MyAnnotation[] value();   
}

注解2

@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {   
    int value();
}

有使用@Repeatable()时的使用

@MyAnnotation(1)
@MyAnnotation(2)
@MyAnnotation(3)
public class MyTest { ... }

没使用@Repeatable()时的使用,@MyAnnotation去掉@Repeatable元注解

@MyAnnotations({
    @MyAnnotation(1), 
    @MyAnnotation(2),
    @MyAnnotation(3)})
public class MyTest { ... }

这个注解还是非常有用的,让我们的代码变得简洁不少,
Spring@ComponentScan注解也用到这个元注解。

元素的类型

支持的元素类型

  • 8种基本数据类型(byteshortcharintlongfloatdoubleboolean

  • String

  • Class

  • enum

  • 注解类型

  • 数组(所有上边类型的数组)

例子

枚举类

public enum Status {
    GOOD,
    BAD
}

注解1

@Target(ElementType.ANNOTATION_TYPE)
public @interface MyAnnotation1 {
    int val();
}

注解2

@Target(ElementType.TYPE)
public @interface MyAnnotation2 {
    
    boolean boo() default false;
    
    Class> cla() default Void.class;
    
    Status enu() default Status.GOOD;
    
    MyAnnotation1 anno() default @MyAnnotation1(val = 1);
    
    String[] arr();
    
}

使用时,无默认值的元素必须传值

@MyAnnotation2(
        cla = String.class,
        enu = Status.BAD,
        anno = @MyAnnotation1(val = 2),
        arr = {"a", "b"})
public class MyTest { ... }

Java内置的注解

@Override注解

告诉编译器这个是个覆盖父类的方法。如果父类删除了该方法,则子类会报错。

@Deprecated注解

表示被注解的元素已被弃用。

@SuppressWarnings注解

告诉编译器忽略警告。

@FunctionalInterface注解

Java 1.8 引入的注解。该注释会强制编译器javac

이후의 주석 형식은 🎜
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnno {   
    String value();   
}
🎜주석이 있는 요소 선언에는 두 가지 형식이 있습니다🎜
@MyAnno("class")
public class MyClass {
    
    @MyAnno("feild")
    private String str;
    
    @MyAnno("method")
    public void method() { }
    
}

공통 메타 주석

@Target 주석

🎜 @Target 주석은 주석이 적용될 수 있는 항목을 제한하는 데 사용됩니다. @Target이 없는 주석은 모든 항목에 적용될 수 있습니다. 🎜🎜java.lang.annotation.ElementType 클래스🎜
  • @Target이 허용하는 모든 항목을 볼 수 있습니다. >🎜TYPE [클래스, 인터페이스, 주석]에 🎜 사용
  • 🎜FIELD [필드, 열거 상수]에 🎜 사용 li>🎜METHOD [Method]에서 🎜
  • 🎜PARAMETER 사용 🎜
  • 🎜CONSTRUCTOR사용 > [생성자]에 🎜
  • 🎜LOCAL_VARIABLE 사용 [로컬 변수]에 🎜
  • 🎜 사용 ANNOTATION_TYPE 🎜 사용 [주석]의 li>
  • 🎜PACKAGE 🎜
  • 🎜TYPE_PARAMETER 사용 Java 1.8을 사용하여 🎜
  • 🎜 소개 TYPE_USE Java 1.8을 사용하여 🎜
  • 🎜@Test 주석을 도입하면 메소드에만 사용할 수 있습니다. 🎜
public class Test {
    
    public static void main(String[] args) throws Exception {
    
        MyClass obj = new MyClass();
        Class> clazz = obj.getClass();
        
        // 获取对象上的注解
        MyAnno anno = clazz.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取属性上的注解
        Field field = clazz.getDeclaredField("str");
        anno = field.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取方法上的注解
        Method method = clazz.getMethod("method");
        anno = method.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
    }
    
}
🎜여러 항목을 지원하려면 여러 값을 전달하세요. 🎜
@CmdMapping(Cmd.LOGIN)
public class LoginHandler implements ICmdHandler {
    @Override
    public void handle() {
        System.out.println("handle login request");
    }
}

@CmdMapping(Cmd.LOGOUT)
public class LogoutHandler implements ICmdHandler {
    @Override
    public void handle() {
        System.out.println("handle logout request");
    }
}
🎜또한 메타 주석도 주석이며 @Target 주석과 같은 주석 구문을 따릅니다.
@Target(ElementType.ANNOTATION_TYPE)@Target 주석이 주석에만 사용될 수 있음을 나타냅니다. 🎜
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CmdMapping {
    int value();   
}

@RetentionAnnotation

🎜@Retention은 주석을 보관해야 하는 기간을 지정합니다. 기본값은 RetentionPolicy.CLASS입니다. >.
java.lang.annotation.RetentionPolicy🎜
  • 🎜SOURCE에서 모든 항목을 볼 수 있습니다. 클래스 파일에 포함됨🎜
  • 🎜CLASS 클래스 파일에 포함됨, 가상 머신에 로드되지 않음🎜
  • 🎜RUNTIME 클래스 파일에 포함되어 있으며 가상 머신에 의해 로드되고 리플렉션 API를 통해 얻을 수 있습니다🎜
🎜@Test 주석이 가상 머신에 로드되고 코드를 통해 얻을 수 있습니다🎜
public interface Cmd {
    int REGISTER = 1;
    int LOGIN    = 2;
    int LOGOUT   = 3;
}

@Documented주석

🎜은 주로 보관 도구 식별에 사용됩니다. 주석이 달린 요소는 Javadoc 또는 유사한 도구를 사용하여 문서화할 수 있습니다. 🎜

@InheritedAnnotation

🎜@Inherited 주석의 주석이 추가되고 주석이 달린 클래스의 하위 클래스에도 이 주석이 있습니다🎜🎜 Annotation🎜
public interface ICmdHandler { 
    void handle();   
}
🎜Parent class🎜
@Component
public class HandlerDispatcherServlet implements 
    InitializingBean, ApplicationContextAware {

    private ApplicationContext context;

    private Map<integer> handlers = new HashMap();
    
    public void handle(int cmd) {
        handlers.get(cmd).handle();
    }
    
    public void afterPropertiesSet() {
        
        String[] beanNames = this.context.getBeanNamesForType(Object.class);

        for (String beanName : beanNames) {
            
            if (ScopedProxyUtils.isScopedTarget(beanName)) {
                continue;
            }
            
            Class> beanType = this.context.getType(beanName);
            
            if (beanType != null) {
                
                CmdMapping annotation = AnnotatedElementUtils.findMergedAnnotation(
                        beanType, CmdMapping.class);
                
                if(annotation != null) {
                    handlers.put(annotation.value(), (ICmdHandler) context.getBean(beanType));
                }
            }
        }
        
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {   
        this.context = applicationContext;
    }

}</integer>
🎜 하위 클래스 ChildParent🎜
@ComponentScan("pers.custom.annotation")
public class Main {

    public static void main(String[] args) {
        
        AnnotationConfigApplicationContext context 
            = new AnnotationConfigApplicationContext(Main.class);
            
        HandlerDispatcherServlet servlet = context.getBean(HandlerDispatcherServlet.class);
        
        servlet.handle(Cmd.REGISTER);
        servlet.handle(Cmd.LOGIN);
        servlet.handle(Cmd.LOGOUT);

        context.close();
    }
}

에 추가된 <code>@MyAnnotation를 상속합니다 @ 반복 가능주석

🎜Java 1.8에 도입된 주석은 해당 주석이 재사용 가능함을 나타냅니다. 🎜🎜Annotation 1🎜rrreee🎜Annotation 2🎜rrreee🎜@Repeatable()을 사용할 때 사용 🎜rrreee🎜@Repeatable()을 사용하지 않을 때 사용, @MyAnnotation@Repeatable 메타 주석을 제거하세요🎜rrreee🎜이 주석은 여전히 ​​매우 유용하여 코드를 훨씬 단순하게 만들어줍니다.
Spring@ComponentScan 주석도 이 메타 주석을 사용합니다. 🎜

요소 유형

지원되는 요소 유형

  • 🎜8가지 기본 데이터 유형(byte code> , <code>short, char, int, long, float, double , 부울)🎜
  • 🎜문자열🎜
  • 🎜클래스 🎜
  • 🎜enum🎜
  • 🎜주석 유형🎜
  • 🎜Array(위의 모든 유형의 배열)🎜
  • ul>

    🎜Enumeration 클래스🎜rrreee🎜Annotation 1🎜rrreee🎜Annotation 2🎜rrreee🎜사용 시 기본값이 없는 요소는 값을 전달해야 합니다🎜rrreee

    Java내장 주석

    @Override주석

    🎜은 이것이 상위 클래스를 재정의하는 메서드임을 컴파일러에 알려줍니다. 상위 클래스가 이 메서드를 삭제하면 하위 클래스에서 오류를 보고합니다. 🎜

    @Deprecated 주석

    🎜은 주석이 달린 요소가 더 이상 사용되지 않음을 나타냅니다. 🎜

    @SuppressWarnings 주석

    🎜은 컴파일러에게 경고를 무시하도록 지시합니다. 🎜

    @FunctionalInterface주석

    🎜Java 1.8에 도입된 주석입니다. 이 주석은 컴파일러 javac가 인터페이스가 기능적 인터페이스 표준을 준수하는지 확인하도록 강제합니다. 🎜

    特别的注解

    有两种比较特别的注解

    • 标记注解 : 注解中没有任何元素,使用时直接是 @XxxAnnotation, 不需要加括号

    • 单值注解 : 注解只有一个元素,且名字为value,使用时直接传值,不需要指定元素名@XxxAnnotation(100)

    利用反射获取注解

    JavaAnnotatedElement接口中有getAnnotation()等获取注解的方法。
    MethodFieldClassPackage等类均实现了这个接口,因此均有获取注解的能力。

    例子

    注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnno {   
    String value();   
}

被注解的元素

@MyAnno("class")
public class MyClass {
    
    @MyAnno("feild")
    private String str;
    
    @MyAnno("method")
    public void method() { }
    
}

获取注解

public class Test {
    
    public static void main(String[] args) throws Exception {
    
        MyClass obj = new MyClass();
        Class> clazz = obj.getClass();
        
        // 获取对象上的注解
        MyAnno anno = clazz.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取属性上的注解
        Field field = clazz.getDeclaredField("str");
        anno = field.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取方法上的注解
        Method method = clazz.getMethod("method");
        anno = method.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
    }
    
}

Spring中使用自定义注解

注解本身不会有任何的作用,需要有其他代码或工具的支持才有用。

需求

设想现有这样的需求,程序需要接收不同的命令CMD
然后根据命令调用不同的处理类Handler
很容易就会想到用Map来存储命令和处理类的映射关系。

由于项目可能是多个成员共同开发,不同成员实现各自负责的命令的处理逻辑。
因此希望开发成员只关注Handler的实现,不需要主动去Map中注册CMDHandler的映射。

最终效果

最终希望看到效果是这样的

@CmdMapping(Cmd.LOGIN)
public class LoginHandler implements ICmdHandler {
    @Override
    public void handle() {
        System.out.println("handle login request");
    }
}

@CmdMapping(Cmd.LOGOUT)
public class LogoutHandler implements ICmdHandler {
    @Override
    public void handle() {
        System.out.println("handle logout request");
    }
}

开发人员增加自己的Handler,只需要创建新的类并注上@CmdMapping(Cmd.Xxx)即可。

具体做法

具体的实现是使用Spring和一个自定义的注解
定义@CmdMapping注解

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CmdMapping {
    int value();   
}

@CmdMapping中有一个int类型的元素value,用于指定CMD。这里做成一个单值注解。
这里还加了Spring@Component注解,因此注解了@CmdMapping的类也会被Spring创建实例。

然后是CMD接口,存储命令。

public interface Cmd {
    int REGISTER = 1;
    int LOGIN    = 2;
    int LOGOUT   = 3;
}

之后是处理类接口,现实情况接口会复杂得多,这里简化了。

public interface ICmdHandler { 
    void handle();   
}

上边说过,注解本身是不起作用的,需要其他的支持。下边就是让注解生效的部分了。
使用时调用handle()方法即可。

@Component
public class HandlerDispatcherServlet implements 
    InitializingBean, ApplicationContextAware {

    private ApplicationContext context;

    private Map<integer> handlers = new HashMap();
    
    public void handle(int cmd) {
        handlers.get(cmd).handle();
    }
    
    public void afterPropertiesSet() {
        
        String[] beanNames = this.context.getBeanNamesForType(Object.class);

        for (String beanName : beanNames) {
            
            if (ScopedProxyUtils.isScopedTarget(beanName)) {
                continue;
            }
            
            Class> beanType = this.context.getType(beanName);
            
            if (beanType != null) {
                
                CmdMapping annotation = AnnotatedElementUtils.findMergedAnnotation(
                        beanType, CmdMapping.class);
                
                if(annotation != null) {
                    handlers.put(annotation.value(), (ICmdHandler) context.getBean(beanType));
                }
            }
        }
        
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {   
        this.context = applicationContext;
    }

}</integer>

主要工作都是Spring做,这里只是将实例化后的对象putMap中。

测试代码

@ComponentScan("pers.custom.annotation")
public class Main {

    public static void main(String[] args) {
        
        AnnotationConfigApplicationContext context 
            = new AnnotationConfigApplicationContext(Main.class);
            
        HandlerDispatcherServlet servlet = context.getBean(HandlerDispatcherServlet.class);
        
        servlet.handle(Cmd.REGISTER);
        servlet.handle(Cmd.LOGIN);
        servlet.handle(Cmd.LOGOUT);

        context.close();
    }
}

> 完整项目

总结

可以看到使用注解能够写出很灵活的代码,注解也特别适合做为使用框架的一种方式。
所以学会使用注解还是很有用的,毕竟这对于上手框架或实现自己的框架都是非常重要的知识。

위 내용은 Java 주석의 정의 및 사용 소개(코드 예제)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 segmentfault에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까?고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까?Mar 17, 2025 pm 05:46 PM

이 기사에서는 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 및 Gradle을 사용하여 접근 방식과 최적화 전략을 비교합니다.

적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까?적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까?Mar 17, 2025 pm 05:45 PM

이 기사에서는 Maven 및 Gradle과 같은 도구를 사용하여 적절한 버전 및 종속성 관리로 사용자 정의 Java 라이브러리 (JAR Files)를 작성하고 사용하는 것에 대해 설명합니다.

카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까?카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까?Mar 17, 2025 pm 05:44 PM

이 기사는 카페인 및 구아바 캐시를 사용하여 자바에서 다단계 캐싱을 구현하여 응용 프로그램 성능을 향상시키는 것에 대해 설명합니다. 구성 및 퇴거 정책 관리 Best Pra와 함께 설정, 통합 및 성능 이점을 다룹니다.

캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까?캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까?Mar 17, 2025 pm 05:43 PM

이 기사는 캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA를 사용하는 것에 대해 설명합니다. 잠재적 인 함정을 강조하면서 성능을 최적화하기위한 설정, 엔티티 매핑 및 모범 사례를 다룹니다. [159 문자]

Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까?Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까?Mar 17, 2025 pm 05:35 PM

Java의 클래스 로딩에는 부트 스트랩, 확장 및 응용 프로그램 클래스 로더가있는 계층 적 시스템을 사용하여 클래스로드, 링크 및 초기화 클래스가 포함됩니다. 학부모 위임 모델은 핵심 클래스가 먼저로드되어 사용자 정의 클래스 LOA에 영향을 미치도록합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

WebStorm Mac 버전

WebStorm Mac 버전

유용한 JavaScript 개발 도구

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.