java基础知识-基本概念
1.1 java语言有哪些优点?
1.java语言为纯面向对象的语言。
2.平台无关性。java语言的优点便是“一次编译,到处执行”。编译后的程序不会被平台所约束,因此java语言有很好的移植性。
3.java提供了许多内置的类库,将代码封装好来给操作人员使用,从而大大减少开发人员的时间。
4.提供了对web应用的开发的支持。
5.具有较好的安全性和健壮性。
6.去除了c++语言中难以理解,容易混淆的特性,例如头文件,指针,结构,单元运算符重载,虚拟基础类,多重继承等,所以java语言是由c++语言改进并重新设计而来的
1.2 java语言和c/c++有什么异同。
java和C++都是面向对象的语言,都使用了面向对象的思想(例如封装,继承,多态),由于面向对象有许多非常好的特性(继承,组合等),因此二者都有很好的重用性。
下面重点说一下不同点:
1.java为解释型语言,c/c++为编译型语言,java代码由java编译器编译成字节码,然后由JVM解释,C语言代码经过编译和链接生成可执行的二进制代码,因此java的执行速度比c++慢,但是java可跨平台执行,c/c++不能
2.java语言没有指针
3.java只能实现单重继承,但是可以引入多个接口
4.java为纯面向对象语言,所有代码必须在类里实现
5.java语言提供了垃圾回收器来实现对垃圾的自动回收,c++语言中需要开发人员去管理对内存的分配。C语言,通常会把释放资源的代码放在析构函数中,Java没有但是有finalize()方法。
java语言不支持运算符重载,C语言支持
java不支持默认函数参数,c语言支持
java不提供goto语句,c/c++支持,但是在java中goto为保留关键字
java不支持自动强制类型装换,c语言支持
java具有平台无关性,就是对每种数据类型分配固定长度。
java提供对注释文档的内建支持
java包含了一些标准库
1.3 为什么使用public static void main(String[] args)方法?
main是程序的入口方法,所以程序执行时第一个执行的方法就是main方法。
main()方法定义的其他几种格式:
1.static pubic void main(String[] args)
static 和public无先后顺序
2.public static final void main(String[] args)
可以定义为final
3.static public synchronized void main(String[] args)
可以定义为synchronized
不管哪种定义方式,必须保证main()方法类型为void并且有static和public关键字修饰。不可以用abstract关键字,因为main()为程序的入口方法。
1.4静态块
静态块会在类被加载时调用,可以在main()方法前执行
例如:
public class jingtaikuai {
public static void main(String[] args) {
System.out.println("hello word");
}
static{
System.out.println("静态块");
}
}
执行结果:
静态块 hello word
1.5 java程序初始化顺序是怎样的
java程序的初始化一般遵循三个原则(优先级依次递减):
1.静态对象优先于非静态对象
2.父类优先于子类
3.按照成员变量定义顺序进行初始化
常见面试题:
下面代码的运行结果是什么?
class B extends Object{
static {
System.out.println("load b1");
}
public B(){
System.out.println("create b");
}
static{
System.out.println("load b2");
}
}
class A extends B{
static {
System.out.println("load a");
}
public A(){
System.out.println("create a");
}
}
public class 初始化顺序 {
public static void main(String[] args) {
new A();
}
}
执行结果:
load b1 load b2 load a create b create a
1.6 java作用域
在Java语言中,变量的类型主要有3种:成员变量、静态变量和局部变量
首先说静态变量跟局部变量
静态变量不依赖于特定的实例,而是被所有实例共享,也就是说,只要一个类被加载,JVM就会给类的静态变量分配
存储空间。因此可以通过类名.变量名来访问静态变量
局部变量的作用域与可见性为它所在的花括号内
类的成员变量的作用范围同类的实例化对象的作用范围相同。当类被实例化的时候,成员变量就会在内存中分配空间,并初始化。
直到类的实例化对象的生命周期结束时,成员变量的生命周期才结束。
作用域与可见性 | 当前类 | 同一package | 子类 | 其他package |
---|---|---|---|---|
public | √ | √ | √ | √ |
private | √ | × | × | × |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
重点说一下protected和default:
protected:表名成员变量或方法对该类自身,与它在同一个包中的其他类,在其他包中的该类的子类都可见
default:表明该成员变量或方法只有自己和与其位于同一包内的类可见。
若父类与子类处于同一包内,则子类对父类的default成员变量或方法都有访问权限;若父类与子类处于不同的package内,则没有访问权限
还有需要注意的是,这些修饰符只能修饰成员变量,不能修饰局部变量。
private和protected不能用来修饰类
1.7 一个java文件中能否定义多个类
一个java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名必须和文件名相同。
1.8 java的构造函数
一、什么是构造函数
java构造函数,也叫构造方法,是java中一种特殊的函数。函数名与相同,无返回值。
作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法。
在现实生活中,很多事物一出现,就天生具有某些属性和行为。比如人一出生,就有年龄、身高、体重、就会哭;汽车一出产,就有颜色、有外观、可以运行等。这些,我们就可以将这些天然的属性和行为定义在构造函数中,当new实例化对象时,也就具有这些属性和方法了,没必要再去重新定义了,从而加快了编程效率。
构造函数是对象一建立就运行,给对象初始化,就包括属性,执行方法中的语句。
而一般函数是对象调用才执行,用".方法名“的方式,给对象添加功能。
一个对象建立,构造函数只运行一次。
而一般函数可以被该对象调用多次。
二、构造函数的特点
1、函数名与类名相同
2、不用定义返回值类型。(不同于void类型返回值,void是没有具体返回值类型;构造函数是连类型都没有)
3、不可以写return语句。(返回值类型都没有,也就不需要return语句了)
注:一般函数不能调用构造函数,只有构造函数才能调用构造函数。
三、示例
1、无参构造函数中只定义了一个方法。new对象时,就调用与之对应的构造函数,执行这个方法。不必写“.方法名”。
package javastudy;
public class ConfunDemo {
public static void main(String[] args) {
Confun c1=new Confun(); //输出Hello World。new对象一建立,就会调用对应的构造函数Confun(),并执行其中的println语句。
}
}
class Confun{
Confun(){ //定义构造函数,输出Hello World
System.out.println("Hellow World");
}
}
输出:Hellow World
2、有参构造函数,在new对象时,将实参值传给private变量,相当于完成setter功能。
package javastudy;
public class ConfunDemo3 {
public static void main(String[] args){
Person z=new Person("zhangsan",3); //实例化对象时,new Person()里直接调用Person构造函数并转转实参,相当于setter功能
z.show();
}
}
class Person{
private String name;
private int age;
public Person(String n,int m){ //有参数构造函数,实现给private成员变量传参数值的功能
name=n;
age=m;
}
//getter //实例化对象时,完成了sett功能后,需要getter,获取实参值。
public String getName(){
return name;
}
public int getAget(){
return age;
}
public void show(){ //获取private值后,并打印输出
System.out.println(name+"\n"+age);
}
}
输出: zhangsan 3
以上代码,我们也可以将show()方法中的输出语句直接放在构造函数中,new对象时,即可直接输出值,如下
package javastudy;
public class ConfunDemo3 {
public static void main(String[] args){
Person z=new Person("zhangsan",3); //实例化对象时,new Person()里直接调用Person构造函数并转转实参,同时执行输出语句
}
}
class Person{
private String name;
private int age;
public Person(String n,int m){ //有参数构造函数,实现给private成员变量传参数值的功能,同时直接输出值
name=n;
age=m;
System.out.println(name+"\n"+age);
}
}
输出: zhangsan 3
或
class ConFun
{
public static void main(String[] args){
Person z=new Person(20,"zhangsan");
System.out.println(z.getAge()+z.getName());
}
}
class Person
{
private int age;
private String name;
public Person(int x,String y){
age=x;
name=y;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
}
3、一个对象建立后,构造函数只运行一次。
如果想给对象的值再赋新的值,就要使用set和get方法,此时是当做一般函数使用
如下:
package javastudy;
public class ConfunDemo4 {
public static void main(String[] args) {
PersonDemo s=new PersonDemo("李三",33); //new对象时,即调用对应的构造函数,并传值。同时,不能new同一个对象多次,否则会报错。
s.setName("李五"); //对象建立后,想变更值时,就要用set/get方法,重新设置新的值
s.setName("阿尔法狗"); //并可调用对象多次。
s.print();
}
}
class PersonDemo{
private String name;
private int age;
PersonDemo(String n,int m){ //建立有参构造函数,用于给两个private变量name、age赋值,同时输出值
name=n;
age=m;
System.out.println("姓名:"+name+"年龄:"+age);
}
public void setName(String x){ //set方法,用于再次给name赋值
name=x;
}
public String getName(){ //get方法,用于获取name的赋值
return name;
}
public void print(){
System.out.println(name);
}
}
输出结果:
姓名:李三年龄:33 阿尔法狗
四、默认构造函数
当一个类中没有定义构造函数时,系统会给该类中加一个默认的空参数的构造函数,方便该类初始化。只是该空构造函数是隐藏不见的。
如下,Person(){}这个默认构造函数是隐藏不显示的。
class Person
{
//Person(){}
}
当在该类中自定义了构造函数,默认构造函数就没有了。
如果仍要构造函数,则需要自己在类中手动添加。
五、构造函数的重载
构造函数也是函数的一种,同样具备函数的重载(Overloding)特性。
class Person
{
private String name;
private int age; Person()
{
System.out.println("A:name="+name+":::age="+age);
} Person(String n)
{
name = n;
System.out.println("B:name="+name+":::age="+age);
} Person(String n,int a)
{
name=n;
age=a;
System.out.println("C:name="+name+":::age="+age);
} } class PersonDemo2
{
public static void main(String[] args)
{
Person p1=new Person();
Person p2=new Person("lishi");
Person p3=new Person("lishi",10);
}
}
输出结果: A:name=null:::age=0 B:name=lishi:::age=0 C:name=lishi:::age=10
class Person
{
private String name;
private int age; Person()
{
System.out.println("A:name="+name+":::age="+age);
cry();
} Person(String n)
{
name = n;
System.out.println("B:name="+name+":::age="+age);
cry();
} Person(String n,int a)
{
name=n;
age=a;
System.out.println("C:name="+name+":::age="+age);
cry(); }
void cry()
{
System.out.println("Cry...............");
} } class PersonDemo2
{
public static void main(String[] args)
{
Person p1=new Person();
Person p2=new Person("lishi");
Person p3=new Person("lishi",10);
}
}
输出结果: A:name=null:::age=0 Cry............... B:name=lishi:::age=0 Cry............... C:name=lishi:::age=10 Cry...............
转自:http://www.cnblogs.com/ibelieve618/p/6364541.html
1.9 java中的clone方法
java中所有的类都继承自Object类,这个类提供了一个clone的方法,这个方法的作用是返回一个Object对象的复制。
使用步骤:
1.继承Cloneable 接口
2.重写clone()方法
3.clone方法中调用super.clone()
4.把浅复制的引用指向原型对象新的克隆体
一、简单用法
只需要在需要clone的对象上实现(implements)Cloneable接口,然后再在类中加上clone方法,在方法中只需要调用super.clone(),根据自己的需要实现即可。
public class Student implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
public static void main(String[] args) {
Student stu = new Student();
stu.setAge(1);
stu.setName("aa");
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName());
try {
Student sC = stu.clone();
System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName());
sC.setAge(12);
sC.setName("bb");
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName());
System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName());
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出结果:
testClone.Student@15db9742 age: 1 name: aa testClone.Student@6d06d69c sC.age: 1 sC.name: aa testClone.Student@15db9742 age: 1 name: aa testClone.Student@6d06d69c sC.age: 12 sC.name: bb
分析结果:1、根据输出结果中前边的类名,可以得出被克隆对象的与原来的对象是同一种类型。2、根据内存地址(hashcode)知道,被克隆对象的与原来的对象是存在于内存中的不同的两个对象。所以后边有一个赋值,对原来对象没有任何影响。
二、“影子”克隆与深度克隆
首先看一个例子:
class Bag{//学生的书包
private int width;
private String logo;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
}
public class Student2 implements Cloneable {
private String name;
private int age;
private Bag bag; public Bag getBag() {
return bag;
}
public void setBag(Bag bag) {
this.bag = bag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Student2 clone() throws CloneNotSupportedException {
return (Student2)super.clone();
}
public static void main(String[] args) {
Student2 stu = new Student2();
stu.setAge(1);
stu.setName("aa");
Bag b = new Bag();
b.setWidth(10);
b.setLogo("Nike");
stu.setBag(b);
printStudent(stu);
try {
Student2 sC = stu.clone();
printStudent(sC);
sC.setAge(12);
sC.setName("bb");
sC.getBag().setWidth(100);//改变书包的属性
sC.getBag().setLogo("JNike");
printStudent(stu);
printStudent(sC);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 输出
* @param stu
*/
private static void printStudent(Student2 stu) {
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() +
" bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " +
stu.getBag().getWidth() + ")");
}
} 输出结果: testClone.Student2@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student2@7852e922 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student2@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(JNike width: 100) testClone.Student2@7852e922 age: 12 name: bb bag: testClone.Bag@6d06d69c(JNike width: 100)
分析:发现是不是跟预期的不太一样,通过第二个同学改变书包,但是第一个同学的书包也被改变了。并且通过内存地址可知,他们是同一对象(书包)。原因:调用Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内 容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对 象中相应的变量指向的是同一个对象。 这就是所谓的“影子”克隆。
解决方案:深度克隆,既是对里边的引用也要克隆。以下是实现:
class Bag implements Cloneable{//学生的书包
private int width;//宽
private String logo;//品牌
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
} @Override
protected Bag clone() throws CloneNotSupportedException {
return (Bag)super.clone();
}
}
public class Student3 implements Cloneable {
private String name;
private int age;
private Bag bag; public Bag getBag() {
return bag;
}
public void setBag(Bag bag) {
this.bag = bag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Student3 clone() throws CloneNotSupportedException {
Student3 stu = (Student3)super.clone();
stu.bag = bag.clone();
return stu;
}
public static void main(String[] args) {
Student3 stu = new Student3();
stu.setAge(1);
stu.setName("aa");
Bag b = new Bag();
b.setWidth(10);
b.setLogo("Nike");
stu.setBag(b);
printStudent(stu);
try {
Student3 sC = stu.clone();
printStudent(sC);
sC.setAge(12);
sC.setName("bb");
sC.getBag().setWidth(100);//改变书包的属性
sC.getBag().setLogo("JNike");
printStudent(stu);
printStudent(sC);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 输出
* @param stu
*/
private static void printStudent(Student3 stu) {
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() +
" bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " +
stu.getBag().getWidth() + ")");
}
}
输出: testClone.Student3@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student3@7852e922 age: 1 name: aa bag: testClone.Bag@4e25154f(Nike width: 10) testClone.Student3@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student3@7852e922 age: 12 name: bb bag: testClone.Bag@4e25154f(JNike width: 100)
1.10 什么是反射机制
Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为Java 的反射机制。
Class 类与java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每个类都实现了Member 接口)。这些类型的对象时由JVM 在运行时创建的,用以表示未知类里对应的成员。
这样你就可以使用Constructor 创建新的对象,用get() 和set() 方法读取和修改与Field 对象关联的字段,用invoke() 方法调用与Method 对象关联的方法。另外,还可以调用getFields() getMethods() 和 getConstructors() 等很便利的方法,以返回表示字段,方法,以及构造器的对象的数组。这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。
二、获取字节码的方式
在Java 中可以通过三种方法获取类的字节码(Class)对象
通过Object 类中的getClass() 方法,想要用这种方法必须要明确具体的类并且创建该类的对象。
所有数据类型都具备一个静态的属性.class 来获取对应的Class 对象。但是还是要明确到类,然后才能调用类中的静态成员。
只要通过给定类的字符串名称就可以获取该类的字节码对象,这样做扩展性更强。通过Class.forName() 方法完成,必须要指定类的全限定名,由于前两种方法都是在知道该类的情况下获取该类的字节码对象,因此不会有异常,但是Class.forName() 方法如果写错类的路径会报 ClassNotFoundException 的异常。
ackage com.jas.reflect;
public class ReflectTest {
public static void main(String[] args) {
Fruit fruit = new Fruit();
Class<?> class1 = fruit.getClass(); //方法一
Class<?> class2 = Fruit.class; //方法二
Class class3 = null;
try { //方法三,如果这里不指定类所在的包名会报 ClassNotFoundException 异常
class3 = Class.forName("com.jas.reflect.Fruit");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(class1 + " " +class2 + " " + class3);
}
}
class Fruit{}
三、通过反射机制获取类信息
通过反射机制创建对象,在创建对象之前要获得对象的构造函数对象,通过构造函数对象创建对应类的实例。
下面这段代码分别在运行期间创建了一个无参与有参的对象实例。由于getConstructor() 方法与newInstance() 方法抛出了很多异常(你可以通过源代码查看它们),这里就简写了直接抛出一个Exception,下同。
package com.jas.reflect;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args) throws Exception {
Class clazz = null;
clazz = Class.forName("com.jas.reflect.Fruit");
Constructor<Fruit> constructor1 = clazz.getConstructor();
Constructor<Fruit> constructor2 = clazz.getConstructor(String.class);
Fruit fruit1 = constructor1.newInstance();
Fruit fruit2 = constructor2.newInstance("Apple");
}
}
class Fruit{
public Fruit(){
System.out.println("无参构造器Run...........");
}
public Fruit(String type){
System.out.println("有参构造器Run..........." + type);
}
}
输出: 无参构造器Run……….. 有参构造器Run………..Apple
通过反射机制获取Class 中的属性
package com.jas.reflect;
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = null;
Field field = null;
clazz = Class.forName("com.jas.reflect.Fruit");
//field = clazz.getField("num"); getField() 方法不能获取私有的属性
// field = clazz.getField("type"); 访问私有字段时会报 NoSuchFieldException异常
field = clazz.getDeclaredField("type"); //获取私有type 属性
field.setAccessible(true); //对私有字段的访问取消检查
Fruit fruit = (Fruit) clazz.newInstance(); //创建无参对象实例
field.set(fruit,"Apple"); //为无参对象实例属性赋值
Object type = field.get(fruit); //通过fruit 对象获取属性值
System.out.println(type);
}
}
class Fruit{
public int num;
private String type;
public Fruit(){
System.out.println("无参构造器Run...........");
}
public Fruit(String type){
System.out.println("有参构造器Run..........." + type);
}
}
输出: 无参构造器Run……….. Apple
通过反射机制获取Class 中的方法并运行。
package com.jas.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args) throws Exception {
Class clazz = null;
Method method = null;
clazz = Class.forName("com.jas.reflect.Fruit");
Constructor<Fruit> fruitConstructor = clazz.getConstructor(String.class);
Fruit fruit = fruitConstructor.newInstance("Apple"); //创建有参对象实例
method = clazz.getMethod("show",null); //获取空参数show 方法
method.invoke(fruit,null); //执行无参方法
method = clazz.getMethod("show",int.class); //获取有参show 方法
method.invoke(fruit,20); //执行有参方法
}
}
class Fruit{
private String type;
public Fruit(String type){
this.type = type;
}
public void show(){
System.out.println("Fruit type = " + type);
}
public void show(int num){
System.out.println("Fruit type = " + type + ".....Fruit num = " + num);
}
}
输出: Fruit type = Apple Fruit type = Apple…..Fruit num = 20
四、反射机制简单应用(使用简单工厂创建对象)
Class.forName() 生成的结果是在编译时不可知的,因此所有的方法特征签名信息都是在执行时被提取出来的。反射机制能过创建一个在编译期完全未知的对象,并调用该对象的方法。
以下是反射机制与泛型的一个应用,通过一个工厂类创建不同类型的实例。
要创建对象的实例类Apple :
package com.jas.reflect;
public interface Fruit {}
class Apple implements Fruit{}
加载的配置文件config.properties:
Fruit=com.jas.reflect.Apple
工厂类BasicFactory :
package com.jas.reflect;
import java.io.FileReader;
import java.util.Properties;
public class BasicFactory {
private BasicFactory(){}
private static BasicFactory bf = new BasicFactory();
private static Properties pro = null;
static{
pro = new Properties();
try{
//通过类加载器加载配置文件
pro.load(new FileReader(BasicFactory.class.getClassLoader().
getResource("config.properties").getPath()));
}catch (Exception e) {
e.printStackTrace();
}
}
public static BasicFactory getFactory(){
return bf;
}
//使用泛型获得通用的对象
public <T> T newInstance(Class<T> clazz){
String cName = clazz.getSimpleName(); //获得字节码对象的类名
String clmplName = pro.getProperty(cName); //根据字节码对象的类名通过配置文件获得类的全限定名
try{
return (T)Class.forName(clmplName).newInstance(); //根据类的全限定名创建实例对象
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
创建对象实例:
package com.jas.reflect;
public class ReflectTest {
public static void main(String[] args) throws Exception {
Fruit fruit = BasicFactory.getFactory().newInstance(Fruit.class);
System.out.println(fruit);
}
}
输出 com.jas.reflect.Apple@4554617c
上面这个实例通过一个工厂创建不同对象的实例,通过这种方式可以降低代码的耦合度,代码得到了很大程度的扩展,以前要创建Apple 对象需要通过new 关键字创建Apple 对象,如果我们也要创建Orange 对象呢?是不是也要通过new 关键字创建实例并向上转型为Fruit ,这样做是麻烦的。
现在我们直接有一个工厂,你只要在配置文件中配置你要创建对象的信息,你就可以创建任何类型你想要的对象,是不是简单很多了呢?可见反射机制的价值是很惊人的。
Spring 中的 IOC 的底层实现原理就是反射机制,Spring 的容器会帮我们创建实例,该容器中使用的方法就是反射,通过解析xml文件,获取到id属性和class属性里面的内容,利用反射原理创建配置文件里类的实例对象,存入到Spring的bean容器中。
参考书籍: 《Java 编程思想》 Bruce Eckel 著 陈昊鹏 译
1.10 java创建对象的几种方式
通过new实例化一个对象
通过反射机制创建对象
通过clone方法创建一个对象
通过反序列化方式创建一个对象
1.11 package作用
package的作用
package的中文意思是“包”,它是一个比较抽象的逻辑概念,其宗旨是把.java文件 (Java源文件)、.class文件(编译后的文件)以及其他resource文件(例如.xml文件、.avi文件、.mp3文件、.txt文件等)有条理地进行一个组织,以供使用。它类似于Linux文件系统, 有一个根,从根开始有目录和文件,然后目录中嵌套目录。
具体而言,package主要有以下两个作用: 第一,提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package中的类可以存在相同的名字。 第二,对类按功能进行分类,使项目的组织更加清晰。当开发一个有非常多的类的项目时,如果不使用package对类进行分类,而是把所有类都放在一个package下,这样的代码不仅可读性差,而且可维护性也不好,会严重影响开发效率。
2)package的用法
package的用法一般如下(源文件所在目录为当前目录): 1.在每个源文件的开头加上"package packagename;",然后源文件所在目录下创建一个新目录,名称为 packapename。 2.用javac指令编译每个sourcename. java源文件,将生成的sourcename. classname文件复制到packagename 目录。 3.用 java 指令运行程序:java packagename. sourcename。
3)实例 以下是一个简单的程序示例。
package top.itcourse.pkg;
public class TestPackage {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
结果: Hello World!
最新文章
- Windows phone应用开发[17]-xap提交异常处理
- C# GUID转换成16位字符串或19位数字并确保唯一
- 移动互联网实战--Web Restful API设计和基础架构
- Ajax案例:三级联动查询员工的信息(三张表进行内连接)
- js——倒计时
- 02-线性结构3 Pop Sequence
- 【剑指offer】近期公共祖先
- AutoLayout(转)
- php入门自学小展示
- [Regex Expression] Find Sets of Characters
- Spring Jdbc使用like模糊查询
- C#内获取泛型方法及扩展
- Pomelo的Router
- java.sql.SQLException: Value &#39;0000-00-00 00:00:00&#39; can not be represented as java.sql.Timestamp
- cmd 与 bash 基础命令入门
- webpack模块化管理和打包工具
- windbg分析运行在64位环境下的32位程序的dump
- ActiveX、OLE和COM的关系(转自百度文档)
- 逆FizzBuzz问题求最短序列
- STL基础4:deque
热门文章
- .net core 简单集成JWT报No authenticationScheme was specified, and there was no DefaultChallengeScheme found错误
- go语言从例子开始之Example38.排序
- 初学Java if选择语句
- nodeJs express4 框架
- MFC的Dlg和App什么区别?应用程序类与对话框类
- JavaWeb(二):Servlet
- Android 获取手机(ios,android)的设备唯一码(mac地址, IMEI)
- [CF1168D]Anagram Paths
- 【Linux】ssh执行远程命令awk 参数报错问题
- 【HDOJ6610】Game(序列带修莫队)