标签:loader eva put xxx aar ceo depend tab 复杂
在Java语言,当实例化对象时,对象所在类的所有成员变量首先要进行实例化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。
初始化一般遵循3个原则:
加载顺序
参考资料:
首先看一个在知乎上的优秀回答吧:
反射是什么呢?当我们的程序在运行时,需要动态的加载一些类,这些类可能之前用不到,所以不用加载到 JVM,而是在运行时根据需要才加载,这样的好处对于服务器来说不言而喻。
举个例子我们的项目底层有时是用 mysql,有时用 oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection 这两个类我们要用,这时候我们的程序就写得比较动态化,通过 Class tc = Class.forName("com.java.dbtest.TestConnection"); 通过类的全类名让 JVM 在服务器中找到并加载这个类,而如果是 Oracle 则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出 Java 的特性了!
举多个例子,大家如果接触过 spring,会发现当你配置各种各样的 bean 时,是以配置文件的形式配置的,你需要用到哪些 bean 就配哪些,spring 容器就会根据你的需求去动态加载,你的程序就能健壮地运行。
反射 (Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。通过 Class 获取 class 信息称之为反射(Reflection)
简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。
程序中一般的对象的类型都是在编译器确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象地类型在编译器是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译器是未知的。
反射的核心是JVM在运行时才动态或调用方法/访问属性,它不需要事先(写代码的时候或编译器)知道运行对象是谁。
Java反射框架主要提供以下功能:
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
4.在运行时调用任意一个对象的方法
重点:是运行时而不是编译时
很多人都认为反射在实际的 Java 开发应用中并不广泛,其实不然。
当我们在使用 IDE (如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射最重要的用途就是开发各种通用框架
很多框架(比如 Spring )都是配置化的(比如通过 XML 文件配置 JavaBean,Action 之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。
对与框架开发人员来说,反射虽小但作用非常大,它是各种容器实现的核心。而对于一般的开发者来说,不深入框架开发则用反射用的就会少一点,不过了解一下框架的底层机制有助于丰富自己的编程思想,也是很有益的。
获得class对象
1.调用运行时类的本身的.class属性
Class claszz1 = Person.class; sout(claszz1.getName());
2.通过运行时类的对象获取getClass()
Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3.getName());
3.使用Class类的forName静态方法
public static Class<?> forName(String className) // 在JDBC开发中常用此方法加载数据库驱动: Class.forName(driver);
4.了解通过类的加载器ClassLoader()
ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz5 = classLoader.loadClass(className); System.out.println(clazz5.getName());
什么是注解
Annontation 是 Java5 开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation 像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
Java注解时附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到说明、配置的功能。注解不会也不能影响代码时实际逻辑,仅仅起到辅助性的作用。包含在Java.langannotation包中。
简单来说:注解就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,比起执行相对应的处理。
为什么要用注解
传统的方式,我们时通过配置文件.xml来告诉类如何运行的。
有了注解技术以后,我们就可以通过注解告诉类如何运行。
比如:我们以前编写servlet的时候,需要在web.xml文件配置具体的信息。我们使用了注解以后,可以直接在servlet源代码上,增加注解...servlet就被配置到Tomcat上了。也就是说,注解可以给类、方法上注入信息。
这样也是非常直观的,并且servlet规范时推崇这种配置的。
在Java.lang包下存着的5各基本Annotation,重点掌握前三个。
@Override 重写注解
@Deprecated 过时注解
@Deprecated public String toLocaleString() { DateFormat formatter = DateFormat.getDateTimeInstance(); return formatter.format(this); }
@SuppressWarnings 抑制编译器警告注解
@SafeVarargs Java 7“堆污染”警告
@FunctionalInterface 用来指定该接口是函数式接口
import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 水果名称注解 */ @Target(FIELD) @Retention(RUNTIME) @Documented public @interface FruitName { String value() default ""; }
通俗解释
通俗地讲,泛型就是操作类型地占位符,即假设占位符为T,那么此次声明地数据结构操作的数据类型为T类型。
假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型地数组进行排序,该如何实现》答案是可以用Java泛型。
使用Java泛型地概念,我们可以写一个泛型方法来对一个对象数组排序。然后调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。
泛型方法
你可以写一个泛型方法,该方法在调用时可以接受不同类型地参数,根据传递给泛型方法地参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法地规则
1.所有泛型方法声明都有一个类型参数声明部分(用尖括号分隔),该类型参数声明不放在方法返回类型之前(在下面栗子中的<E>)
2.每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于知道一个泛型类型名称地标识符。
3.类型灿书能被用来声明返回值类型,并可以作为泛型方法得到的实际参数书类型的占位符。
4.泛型方法的声明和其他方法一样。注意类型参数只能代表引用类型,不能是原始类型(像int,double,char等)
{ // 泛型方法 printArray public static < E > void printArray( E[] inputArray ) { // 输出数组元素 for ( E element : inputArray ){ System.out.printf( "%s ", element ); } System.out.println(); } public static void main( String args[] ) { // 创建不同类型数组: Integer, Double 和 Character Integer[] intArray = { 1, 2, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { ‘H‘, ‘E‘, ‘L‘, ‘L‘, ‘O‘ }; System.out.println( "整型数组元素为:" ); printArray( intArray ); // 传递一个整型数组 System.out.println( "\n双精度型数组元素为:" ); printArray( doubleArray ); // 传递一个双精度型数组 System.out.println( "\n字符型数组元素为:" ); printArray( charArray ); // 传递一个字符型数组 } }
泛型类
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
public class Box<T> { private T t; public void add(T t) { this.t = t; } public T get() { return t; } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); Box<String> stringBox = new Box<String>(); integerBox.add(new Integer(10)); stringBox.add(new String("菜鸟教程")); System.out.printf("整型值为 :%d\n\n", integerBox.get()); System.out.printf("字符串为 :%s\n", stringBox.get()); } }
类型通配符一般是使用 ?
代替具体的类型参数。例如 List<?>
在逻辑上是 List<String>
,List<Integer>
等所有 List<具体类型实参> 的父类。
类型通配符上限通过形如 List 来定义,如此定义就是通配符泛型值接受 Number 及其下层子类类型。
类型通配符下限通过形如 List<? super Number> 来定义,表示类型只能接受 Number 及其三层父类类型,如 Objec 类型的实例。
理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:
类型 | 概念描述 | 举例 |
---|---|---|
字符 | 人们使用的记号,抽象意义上的一个符号。 | ‘1‘, ‘中‘, ‘a‘, ‘$‘, ‘¥‘, …… |
字节 | 计算机中存储数据的单元,一个 8 位的二进制数,是一个很具体的存储空间。 | 0x01, 0x45, 0xFA, …… |
ANSI 字符串 | 在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。 | "中文123" (占7字节) |
UNICODE 字符串 | 在内存中,如果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。 | L"中文123" (占10字节) |
字节与字符区别
它们完全不是一个位面的概念,所以两者之间没有“区别”这个说法。不同编码里,字符和字节的对应关系不同:
类型 | 概念描述 |
---|---|
ASCII | 一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为 8 位二进制数,换算为十进制。最小值 0,最大值 255。 |
UTF-8 | 一个英文字符等于一个字节,一个中文(含繁体)等于三个字节 |
Unicode | 一个英文等于两个字节,一个中文(含繁体)等于两个字节。符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占 1 个字节的大小,中文句号“。”占 2 个字节的大小。 |
UTF-16 | 一个英文字母字符或一个汉字字符存储都需要 2 个字节(Unicode扩展区的一些汉字存储需要4个字节) |
UTF-32 | 世界上任何字符的存储都需要 4 个字节 |
Java 面向对象的基本思想之一是封装细节并且公开接口。Java 语言采用访问控制修饰符来控制类及类的方法和变量的访问权限,从而向使用者暴露接口,但隐藏实现细节。访问控制分为四种级别:
修饰符 | 当前类 | 同 包 | 子 类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
Java 中字符串对象创建有两种形式,一种为字面量形式,如 String str = "abc";
,另一种就是使用 new 这种标准的构造对象的方法,如 String str = new String("abc");
,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。这一切都是源于 JVM 为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。
工作原理
当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
public class Test { public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; // 以上两个局部变量都存在了常量池中 System.out.println(s1 == s2); // true // new出来的对象不会放到常量池中,内存地址是不同的 String s3 = new String(); String s4 = new String(); /** * 字符串的比较不可以使用双等号,这样会比较内存地址 * 字符串比较应当用equals,可见String重写了equals */ System.out.println(s3 == s4); // false System.out.println(s3.equals(s4)); // true } }
我们使用工具编写的字母加符号的代码,是我们能看懂的高级语言,计算机无法直接理解,计算机需要先对我们编写的代码翻译成计算机语言,才能执行我们编写的程序。
将高级语言翻译成计算机语言有编译,解释两种方式。两种方式只是翻译的时间不同。
1. 编译型语言
编译型语言写得程序在执行之前,需要借助一个程序,将高级语言编写的程序翻译成计算机能懂的机器语言,然后,这个机器语言就能直接执行了,也就是我们常见的(exe文件)。
2. 解释型语言
解释型语言的程序不需要编译,节省了一道工序,不过解释型的语言在运行的时候需要翻译,每个语句都是执行的时候才翻译,对比编译型语言,效率比较低。通俗来讲,就是借助一个程序,且这个程序能试图理解编写的代码,然后按照编写的代码中的要求执行。
3. 脚本语言
脚本语言也是一种解释型语言,又被称为扩建的语言,或者动态语言不需要编译,可以直接使用,由解释器来负责解释。
脚本语言一般都是以文本形式存在,类似于一种命令。
4. 通俗理解编译型语言和解释型语言
同行讨论编译型语言和解释型语言的时候,这么说过,编译型语言相当于做一桌子菜再吃,解释型语言就是吃火锅。解释型的语言执行效率低,类似火锅需要一边煮一边吃。
六个基本原则(参考《设计模式之禅》)
其他原则
项目中用到的原则
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
在 Java 中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类
public class OuterClass { private String str; public void outerDisplay(){ System.out.println("outerClass..."); } public class InnerClass{ public void innerDisplay(){ str = "chenssy..."; //使用外围内的属性 System.out.println(str); outerDisplay(); //使用外围内的方法 } } // 推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 public InnerClass getInnerClass(){ return new InnerClass(); } public static void main(String[] args) { OuterClass outer = new OuterClass(); OuterClass.InnerClass inner = outer.getInnerClass(); inner.innerDisplay(); } } -------------------- chenssy... outerClass...
在成员内部类中要注意两点:
成员内部类中不能存在任何 static 的变量和方法;
成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
组合:各部件之间没有什么关系,只需要组合即可。例如组装电脑,需要new CPU(),new RAM(),new Disk()
public class Computer { public Computer() { CPU cpu=new CPU(); RAM ram=new RAM(); Disk disk=new Disk(); } } class CPU{ } class RAM{ } class Disk{ }
继承:子类需要具有父类的功能,各子类之间有所差异。例如 Shape 类作为父类,子类有 Rectangle,CirCle,Triangle……代码不写了,大家都经常用。
代理:飞机控制类,我不想暴露太多飞机控制的功能,只需部分前进左右转的控制(而不需要暴露发射导弹功能)。通过在代理类中 new 一个飞机控制对象,然后在方法中添加飞机控制类的各个需要暴露的功能。
public class PlaneDelegation{ private PlaneControl planeControl; //private外部不可访问 // 飞行员权限代理类,普通飞行员不可以开火 PlaneDelegation(){ planeControl = new PlaneControl(); } public void speed(){ planeControl.speed(); } public void left(){ planeControl.left(); } public void right(){ planeControl.right(); } }
final class PlaneControl {// final表示不可继承,控制器都能继承那还得了 protected void speed() {} protected void fire() {} protected void left() {} protected void right() {} }
说明:
类型 | 存储 | 取值范围 | 默认值 | 包装类 |
---|---|---|---|---|
整数型 | ||||
byte | 8 | 最大存储数据量是 255,最小 -27,最大 27-1, [-128~127] |
(byte) 0 | Byte |
short | 16 | 最大数据存储量是 65536,[-215,215-1], [-32768,32767],±3万 |
(short) 0 | Short |
int | 32 | 最大数据存储容量是 231-1, [-231,231-1],±21亿,[ -2147483648, 2147483647] |
0 | Integer |
long | 64 | 最大数据存储容量是 264-1, [-263,263-1], ±922亿亿(±(922+16个零)) |
0L | Long |
浮点型 | ||||
float | 32 | 数据范围在 3.4e-45~1.4e38,直接赋值时必须在数字后加上 f 或 F | 0.0f | Float |
double | 64 | 数据范围在 4.9e-324~1.8e308,赋值时可以加 d 或 D 也可以不加 | 0.0d | Double |
布尔型 | ||||
boolean | 1 | true / flase | false | Boolean |
字符型 | ||||
char | 16 | 存储 Unicode 码,用单引号赋值 | ‘\u0000‘ (null) | Character |
jdk5.0
提供的新特特性,它可以自动实现类型的转换// jdk 1.5 public class TestDemo { public static void main(String[] args) { Integer m =10; int i = m; } }
new Integer(123) 与 Integer.valueOf(123) 的区别在于,new Integer(123) 每次都会新建一个对象,而 Integer.valueOf(123) 可能会使用缓存对象,因此多次使用 Integer.valueOf(123) 会取得同一个对象的引用。
Integer x = new Integer(123); Integer y = new Integer(123); System.out.println(x == y); // false Integer z = Integer.valueOf(123); Integer k = Integer.valueOf(123); System.out.println(z == k); // true
编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。
Integer m = 123;
Integer n = 123;
System.out.println(m == n); // true
(Open Closed Principle 简称 OCP):软件实体应当对扩展开放,对修改关闭。要做到开闭有两个要点:①抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;②封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而换乱。
标签:loader eva put xxx aar ceo depend tab 复杂
原文地址:https://www.cnblogs.com/Roni-i/p/10013678.html