
匿名类是一种特殊的内部类,它是在一个表达式内部包含一个完整的类定义。
内部类是在一个类的内部嵌套定义的类,它可以是其它类的成员,也可以在一个语句块的内部定义,还可以在表达式内部匿名定义。
匿名类与其他类的不同就在于匿名,也就是没有名称。
Java中允许创建子类对象时,除了使用父类的构造方法外,还可以用类体。 匿名类就是一个没有类申明的类体,因为没有名称,所有匿名类不可以申明对象,但却可以创建对象。 例如:
A是一个子类,那么下面的代码就是A的一个子类(匿名类)创建对象。
new A(){
匿名类的类体
};
由于匿名类是一个子类,所以和有一般子类的特征。可以继承父类的方法,同样也可以重写父类的方法。值得提醒的是,在使用匿名类时,一定是在某个类中直接用匿名类创建对象,因此匿名类必定是内部类,所以和其他匿名类一样可以访问外嵌类中的成员变量和方法,匿名类的类体中不可以什么。
static成员变量和static方法。
尽管匿名类没有申明的步骤,但可以在创建匿名对象时返回一个引用赋值给匹配参数。 匿名类的常用方式是向方法的参数传值。
具体方法如下:
abstract class Speak{public abstract void speakHello();
}
class Student{
void f(Speak sp){
spspeakHello();
}
}
public class AnonymousClassDemo {
public static void main(String[] args) {
Speak speak = new Speak(){
public void speakHello(){
Systemoutprintln("大家好,祝工作愉快!");
}
};
speakspeakHello();
Student st = new Student();
stf(new Speak(){
public void speakHello(){
Systemoutprintln("I am a student, how are you");
}
});
}
}
上面代码的抽象类改成接口同样适用。
这样xml中配置的bean的属性就会被注入配置文件里面对应的值
首先xml中的bean会在扫描的过程中封装成BeanDefinition对象,property标签会被弄成一个ProprotyValue的集合放在BeanDefinition的ProprotyValues变量中,所以在xml解析完成之后的BeanDefinition的ProprotyValues变量是这样的
上节PropertySourcesPlaceholderConfigurer这个类收集了environment配置信息和本地配置信息,并把它放在了PropertySourcesPropertyResolver的propertySources属性中
最后创建了一个StringValueResolver对象会调用PropertySourcesPropertyResolver来处理配置信息的替换
接下来就是取出所有的BeanDefinition,看看beanDefinition中的属性中是否有${}表达式,有的话就替换
很多的属性都可以用${}来引用配置信息
重点看看属性是如何被替换的
在BeanDefinitionVisitorresolveValue方法中,String类型的走这
最终会调到PropertySourcesPlaceholderConfigurer创建的StringValueResolver匿名对象的实现方法中
这个匿名对象实现的方法又会调用PropertySourcesPropertyResolver来替换值,前面有提到所有的配置信息都在PropertySourcesPropertyResolverpropertySources中,那么接下来的工作就是从这个容器中找到对应的配置信息的key所对应的value
这里在入参时会创建一个PlaceholderResolver的匿名对象,实现的resolvePlaceholder方法将会调用PropertySourcesPropertyResolvergetPropertyAsRawString()
最后返回了被替换成对应配置信息的值
这里就会调用前面创建的匿名对象的实现方法,方法体重会调用调用PropertySourcesPropertyResolvergetPropertyAsRawString(),去用key获取对应的配置信息
PropertySourcesPropertyResolvergetPropertyAsRawString()
PropertiesPropertySource对象内部有name,和source,source是一个泛型,当前类型为Properties,PropertiesPropertySource需要实现getProperty方法,其实就是从source中获取属性值
最后调到了Properties类的get方法,返回value
对每个beanDefination都这样 *** 作过一遍
注意这个StringValueResolver的resolveStringValue会调用PropertySourcesPropertyResolver的方法来处理配置信息的替换,PropertySourcesPropertyResolver持有了所有的配置信息。 那么后面@Value的解析也将StringValueResolver来完成
@Value的解析工作是在Bean实例化后,属性注入的时候从配置文件找出并设置进去的
populateBean方法
只有string类型的才能@Value注解,才需要处理
又是这个容器,之前PropertySourcesPlaceholderConfigurer的doProcessProperties放进去的StringValueResolver
最后又会回到这个地方解析并注入值,和xml方式获取配置信息是一样的
找到对应的配置信息之后,反射设置这个属性的值
想要学习java如果是零基础或是转行学习,第一要看自己的年纪适合适合在学习这方便,第二学历是大专及以上吗(也有大专以下学习的,但是一定要认真刻苦学)
java主要是编程开发,没有特别难学,现在就业的前景也不错,岗位需求量大,只要下定决心学习一定能学好,现在的培训机构也都是有零基础班的,可以先去试试听课,看自己适不适合学。
一、什么是属性描述符?
MDN:
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。
数据描述符是一个拥有可写或不可写值的属性。
存取描述符是由一对 getter-setter 函数功能来描述的属性。
描述符必须是两种形式之一;不能同时是两者。
数据描述符和存取描述符均具有以下可选键值:
value 与属性相关的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
writable true 当且仅当可能用赋值运算符改变与属性相关的值。默认为 false。
存取描述符同时具有以下可选键值:
get
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。方法将返回用作属性的值。默认为 undefined。 set 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将收到作为唯一参数的新值分配给属性。默认为 undefined。
以上是摘自MDN的解释,看起来是很晦涩的,具体什么意思呢: 首先我们从以上解释知道该匿名参数对象有个很好听的名字叫属性描述符,属性描述符又分成两大块:数据描述符以及存取描述符(其实只是一个外号,给指定的属性集合起个外号)。
数据描述符包括两个属性 :value属性以及writable属性,第一个属性用来声明当前欲修饰的属性的值,第二个属性用来声明当前对象是否可写即是否可以修改
存取描述符就包括get与set属性用来声明欲修饰的象属性的getter及setter
属性描述符内部,数据描述符与存取描述符只能存在其中之一,但是不论使用哪个描述符都可以同时设置configurable属性以及enumerable属性。
configurable属性用来声明欲修饰的属性是否能够配置,仅有当其值为true时,被修饰的属性才有可能能够被删除,或者重新配置。
enumerable属性用来声明欲修饰属性是否可以被枚举。
知道了什么是属性描述符,我们就可以开始着手创建一些对象并开始配置其属性
顺便给大家推荐一个裙,它的前面是 537,中间是631,最后就是 707。想要学习前端的小伙伴可以加入我们一起学习,互相帮助。群里每天晚上都有大神免费直播上课,如果不是想学习的小伙伴就不要加啦。
二、创建属性不可配置不可枚举的对象
//使用默认值配置
(function(){
varobj = {};//声明一个空对象
ObjectdefineProperty(obj,"key",{
value:"static"
//没有设置 enumerable 使用默认值 false
//没有 configurable 使用默认值 false
//没有 writable 使用默认值 false
});
consolelog(objkey);//输出 “static”
objkey ="new"//尝试修改其值,修改将失败,因为 writable 为 false
consolelog(objkey);//输出 “static”
obja =1;//动态添加一个属性
for(variteminobj){//遍历所有 obj 的可枚举属性
consolelog(item);
}//只输出一个 “a” 因为 “key”的 enumerable为 false
})();
//显示配置 等价于上面
(function(){
varobj = {};
ObjectdefineProperty(obj,"key",{
enumerable:false,
configurable:false,
writable:false,
value:"static"
})
})();
//等价配置
(function(){
varo = {};
oa =1;
//等价于
ObjectdefineProperty(o,"a",{value:1,
writable:true,
configurable:true,
enumerable:true});
ObjectdefineProperty(o,"a",{value:1});
//等价于
ObjectdefineProperty(o,"a",{value:1,
writable:false,
configurable:false,
enumerable:false});
})();
三、Enumerable 特性
属性特性enumerable决定属性是否能被forin循环或Objectkeys方法遍历得到
(function(){
varo = {};
ObjectdefineProperty(o,"a",{value:1,enumerable:true});
ObjectdefineProperty(o,"b",{value:2,enumerable:false});
ObjectdefineProperty(o,"c",{value:2});//enumerable default to false
od =4;//如果直接赋值的方式创建对象的属性,则这个属性的 enumerable 为 true
for(varitemino){//遍历所有可枚举属性包括继承的属性
consolelog(item);
}
consolelog(Objectkeys(o));//获取 o 对象的所有可遍历属性不包括继承的属性
consolelog(opropertyIsEnumerable('a'));//true
consolelog(opropertyIsEnumerable('b'));//false
consolelog(opropertyIsEnumerable('c'));//false
})();
输出结果如下:
四、Configurable 特性
(function(){
varo = {};
ObjectdefineProperty(o,"a",{get:function(){return1;},
configurable:false} );
//enumerable 默认为 false,
//value 默认为 undefined,
//writable 默认为 false,
//set 默认为 undefined
//抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置
ObjectdefineProperty(o,"a",{configurable:true} );
//抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置,enumerable 的原值为 false
ObjectdefineProperty(o,"a",{enumerable:true} );
//抛出异常,因为最开始定义了 configurable 为 false,set的原值为 undefined
ObjectdefineProperty(o,"a",{set:function(val){}} );
//抛出异常,因为最开始定义了 configurable 为 false,故无法进行覆盖,尽管想用一样的来覆盖
ObjectdefineProperty(o,"a",{get:function(){return1}});
//抛出异常,因为最开始定义了 configurable 为 false,故无法将其进行重新配置把属性描述符从存取描述符改为数据描述符
ObjectdefineProperty(o,"a",{value:12});
consolelog(oa);//输出1
deleteoa;//想要删除属性,将失败
consolelog(oa);//输出1
})();
五、提高及扩展
1属性描述符中容易被误导的地方之writable与configurable
(function(){
varo = {};
ObjectdefineProperties(o,{
"a": {
value:1,
writable:true,//可写
configurable:false//不可配置
//enumerable 默认为 false 不可枚举
},
"b":{
get:function(){
returnthisa;
},
configurable:false
}
});
consolelog(oa);//1
oa =2;//修改值成功,writable 为 true
consolelog(oa);//2
ObjectdefineProperty(o,"a",{value:3});//同样为修改值成功
consolelog(oa);//3
//将其属性 b 的属性描述符从存取描述符重新配置为数据描述符
ObjectdefineProperty(o,"b",{value:3});//抛出异常,因为 configurable 为 false
})();
2通过上面的学习,我们都知道传递属性描述符参数时,是定义一个匿名的对象,里面包含属性描述符内容,若每定义一次便要创建一个匿名对象传入,将会造成内存浪费。故优化如下:
(function(){
varobj = {};
//回收同一对象,即减少内存浪费
functionwithValue(value){
vard = withValued ||(
withValued = {
enumerable:false,
configurable:false,
writable:false,
value:null
}
);
dvalue = value;
returnd;
}
ObjectdefineProperty(obj,"key",withValue("static"))
})();
最后给大家推荐一个裙,它的前面是 537,中间是631,最后就是 707。想要学习前端的小伙伴可以加入我们一起学习,互相帮助。群里每天晚上都有大神免费直播上课,如果不是想学习的小伙伴就不要加啦。
以上就是关于JAVA匿名类是什么,怎么用全部的内容,包括:JAVA匿名类是什么,怎么用、【Spring源码配置文件解析】2. xml注入配置信息 & @Value、JAVA培训课程难不难,好学吗等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)