static、final、abstract 、interface 、字段、属性、方法、构造器 应用场景分析
static (对象是静态的)
-
Static 变量不能在方法体中定义,因为,方法体中的变量为局部变量,局部变量存储在动态存储区
-
静态变量存储在静态存储区,可以认为规定静态变量不能定义在方法体内部。
-
Static方法中不能使用this和super关键字
-
不能调用非static方法,只能访问所属类的静态成员变量和成员方法 因为当static方法被调用的时候这个类的对象可能还没有被创建,即使已经被创建了,也无法确定调用那个对象的方法,
-
static方法也不能访问非static类型的变量。
final (常量:对象只能一次赋值操作)
示例
public class DefaultResourceLoader implements ResourceLoader {
//加载资源的类加载器
@Nullable
private ClassLoader classLoader;
# 用于存储注册的协议解析器
private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet(4);
# 缓存已加载的资源
private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap(4);
复制代码
static 、 final (静态常量:一起使用: 对象为静态且不能修改)
static final 通常定义 一个常数或者字符串反反复复使用时,内存就不会重复申请和释放
示例
(static) 方法是一个很重要的用途是实现单例模式。为了实现这一功能,必须隐藏构造函数,由于构造函数被声明为private,外界无法直接创建这个类型的对象,只能通过该类提供的方法来获取类的对象。要达到这样的目的只能把创建对象的方法上名为static.
private final static SingleTon instance=new SingleTon();
复制代码
/**
* 活动秘钥信息 accessKey为key
*/
public final static Map<String,ShopAccessInfo> SHOP_RSA_MAP = new HashMap<>();
@Component
@ConfigurationProperties(prefix = "prop")
@PropertySource(value = "config/rsa.properties")
public class CustomSecretKeyMap {
/**
* 对接秘钥信息
*/
private List<ShopAccessInfo> shops;
/**
* 获取秘钥信息
* @return
*/
public List<ShopAccessInfo> getShops() {
return shops;
}
/**
* 转换秘钥信息
* @param shops
*/
public void setShops(List<ShopAccessInfo> shops) {
if(CollectionUtils.isEmpty(shops)){
return;
}
this.shops = shops;
for(ShopAccessInfo shop:shops){
ActivityMapUtils.SHOP_RSA_MAP.put(shop.getAccessKey(),shop);
}
}
}
复制代码
abstract
在抽象类,抽象方法本质上是定义接口规范,即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
- abstract常常用于修饰类或方法。
- **写了抽象方法,那么该类前面就要写abstract修饰。
- 父类是抽象类,子类继承该abstract类时,要么子类也是抽象类,也就是abstract修饰该类; 要么就是重写父类(abstract)的抽象方法。,如果父类没有抽象方法,则不用重写!!!
- abstract修饰方法就是为了子类重写该方法,抽象方法不能定义为private
- 抽象类不能创建对象
- 抽象类是不能被实例化的
实例化实际就是在内存中开辟一块空间用于存储新的产物,即对象。
在抽象类中,子类实例化会先初始化父类,但父类初始化并不是创建一个父类对象,而是把父类中定义的对象相关属性都初始化,因为这些属性子类对象也是拥有的。
所以,为了保证子类对象的完整性,要从最底层的父类开始,逐级初始化,所有初始化都完成后才会产生一个完整的子类对象
- 初始化一个对象,创建一个对象需要调用该类的构造方法,而构造方法的意义就是给变量初始化
- 实例化一个对象,java会在内存中生成你new出来的那个类的实例,即对象。然后可以调用这个对象的方法进行操作,获取对象的公共成员等。
- java实例化有4种方式: 一、用new语句创建对象,这是最常用的创建对象方式。 二、运用反射手段,调用## java.lang.Class.newInstance() 或者java.lang.reflect.Constructor类的newInstance实例化方法。 例如: XML配置文件中,获取具体子类的类名称字符串subCLassName,然后根据获得类名字符串进行实例化。
Class c = Class.foName(subClassName);
User user = (User) c.newInstance(); //不带有任何参数
public Object getNewObject(String className) trows Exception {
Class tClass = Class.forName(className);
Object tObject = tClass.newInstance();
return tObject;
}
复制代码
Class c = Class.foName(subClassName);
Constructor con = c.getConstructor(String.class);
User user = (User) con.newInstance("name");
复制代码
三、调用对象的clone方法。
User user1 = new User(1, "mac");
User user2 = null;
user2 = (User) user1.clone();
复制代码
四、运用反序列化机制。 序列化:把对象状态转化为可保持或者传输的格式过程,被序列化的对象必须implments Serializable; 反序列化:把流转换为对象的过程。 远程传输过程中 , 发送各种类型的数据,无论是哪种数据类型,都以二进制序列的形式在网络上传送,发送方需要把这个java对象转换为字节序列,才可以在网络上传送,也就是序列化的过程。
import org.junit.Test;
public class SerializableTest {
@Test
public void test() throws IOException {
Person zizhen = new Person ();
zizhen.age = 31;
zizhen.s = "自珍";
//obj 写入文件
FileOutputStream fileOutputStream = new FileOutputStream("temp"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(a);
fileOutputStream.close();
//通过文件读取obj
FileInputStream fileInputStream = new FileInputStream("temp");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Person zizhenClone = (A) objectInputStream.readObject();
fileInputStream.close();
System.out.println(zizhenClone.age);
System.out.println(zizhenClone.name);
}
}
public class Person implements Serializable {
int age;
String name;
}
//抽象类是不能被实例化的
AbstractApplicationContext abstractApplicationContext =new AbstractApplicationContext() {
@Override
protected void refreshBeanFactory() throws BeansException, IllegalStateException {
}
@Override
protected void closeBeanFactory() {
}
@Override
public ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException {
return null;
}
};
//接口无法被实例化,但是可以被实现。
DefaultResourceLoader defaultResourceLoader =new DefaultResourceLoader();
复制代码
- 静态方法是不允许被重写。
- 如果一个抽象类没有字段,所有方法全部都是[抽象方法]就可以把该抽象类改写为接口(interface)。
// 抽象类Person
publice abstract class Person {
public abstract void work();
public abstract void life();
public abstract void eat();
/**
* Subclasses must implement this method to release their all pressure
* This method gets invoked by {@link #sleep()} after all other activities,etc: work, life , eat.
* <p>Should never throw an exception but rather log shut down the brain failures.
*/
public abstract void sleep();
}
}
复制代码
将抽象类改写成接口
publice interface Person {
void run();
void eat();
}
复制代码
- 接口(interface)就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。
- 接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来,写不写效果都一样。
- 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明抽象类。
- 接口的所有方法都是抽象方法,接口不能定义实例字段。
- Java中,一个类只能继承自另一个类,不能从多个类继承。而一个类可以实现多个接口。
代码示例
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
/**
* Name of the MessageSource bean in the factory.
* If none is supplied, message resolution is delegated to the parent.
* @see MessageSource
*/
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
/**
* Subclasses must return their internal bean factory here. They should implement the
* lookup efficiently, so that it can be called repeatedly without a performance penalty.
* <p>Note: Subclasses should check whether the context is still active before
* returning the internal bean factory. The internal factory should generally be
* considered unavailable once the context has been closed.
* @return this application context's internal bean factory (never {@code null})
* @throws IllegalStateException if the context does not hold an internal bean factory yet
* (usually if {@link #refresh()} has never been called) or if the context has been
* closed already
* @see #refreshBeanFactory()
* @see #closeBeanFactory()
*/
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
复制代码
abstract static 不能 组合起来修饰方法
- abstract修饰的方法无方法体,不能随着类的加载而加载到方法区
- static修饰的方法随着类的加载会被加载到类的方法区;
- abstract还不能与final同时存在,因为final修饰的方法是最终方法,无法被重写,abstract 里面的抽象方法 目的是被派生类重写;
- abstract不能与private同时存在,因为private修饰的方法不可见,无法重写;
interface
- 如果一个抽象类没有字段,所有方法全部都是[抽象方法]就可以把该抽象类改写为接口(interface)。
- 接口(interface)就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from beans <i>created</i> by the FactoryBean. (用于取消引用{@link FactoryBean}实例,区分 FactoryBean 创建的Bean)
For example, if the bean named
{@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject} will return the factory, not the instance returned by the factory.(如果名为{@code myJndiObject}是一个FactoryBean,正在获{@code&myJndiObject}将返回工厂,而不是工厂返回的实例)
*/
public interface BeanFactory {
//常量:如果我们在获取Bean的时候,使用&则获取的是FactoryBean本身对象,否则是获取getObject的代理对象。
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String var1) throws BeansException;
...
}
复制代码
- 接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来,写不写效果都一样。
- 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明抽象类。
- 接口的所有方法都是抽象方法,接口不能定义实例字段。
- Java中,一个类只能继承自另一个类,不能从多个类继承。而一个类可以实现多个接口。
// 抽象类Person
publice abstract class Person {
public abstract void work();
public abstract void life();
public abstract void eat();
/**
* Subclasses must implement this method to release their all pressure
* This method gets invoked by {@link #sleep()} after all other activities,etc: work, life , eat.
* <p>Should never throw an exception but rather log shut down the brain failures.
*/
public abstract void sleep();
}
复制代码
将抽象类改写成接口
publice interface Person {
void run();
void eat();
}
复制代码
interface default方法
实现类可以不必覆写default方法。
- default方法的目的是,当需要给接口新增一个方法时,会涉及到修改全部子类。
- 如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方才去覆写新增方法。
- default方法和抽象类的普通方法是有所不同的,因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。
代码示例
interface Person {
void eat();
String sleep();
}
// 将sleep()方法改为default方法
interface Person {
String eat();
default void sleep() {
System.out.println( "默认睡觉时间 0:00- 8:00 run");
}
}
复制代码
Java8新特性定义一个扩展方法:
public interface Formula {
double calculate(int a);
default double sqrt(int a){
return Math.sqrt(a);
}
}
public class Bootstrap {
public static void main(String[] args){
Formula formula = new Formula(){
public double calculate(int a){
return sqrt(a * 100);
}
// 原本应该实现的sqrt方法由于新特性的出现,变得不再那么冗余了
};
System.out.println(formula.calculate(100));
System.out.println(formula.sqrt(16));
}
}
复制代码
通过该特性,我们将能够很方便的实现接口默认实现类。这个特性在编译器实现的角度来说更接近于Scala的trait。
interface 接口的继承
一个interface可以继承另一个interface,interface继承自interface使用extends,它相当于扩展了接口的方法。
代码示例:
/**
* SPI interface to be implemented by most if not all application contexts.(SPI接口将由大多数(如果不是所有)应用程序上下文实现。)
* Provides facilities to configure an application context in addition(此外,还提供配置应用程序上下文的工具)
* to the application context client methods in the
* {@link org.springframework.context.ApplicationContext} interface.
*(继承 ApplicationContext接口中的应用程序上下文客户端方法)
* <p>Configuration and lifecycle methods are encapsulated here to avoid
* making them obvious to ApplicationContext client code. The present
* methods should only be used by startup and shutdown code.
*
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @since 03.11.2003
*/
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle {
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
String ENVIRONMENT_BEAN_NAME = "environment";
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
void setId(String var1);
void setParent(ApplicationContext var1);
ConfigurableEnvironment getEnvironment();
void setEnvironment(ConfigurableEnvironment var1);
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);
void addApplicationListener(ApplicationListener<?> var1);
void refresh() throws BeansException, IllegalStateException;
void registerShutdownHook();
void close();
boolean isActive();
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
复制代码
抽象类和接口区别
Java的接口特指interface的定义,表示一个接口类型和一组方法签名。而编程接口泛指接口规范,如:方法签名,数据格式,网络接口等
复制代码
抽象类和接口区别: 抽象类(abstract class): 继承:只能extends一个class 字段:可以定义实例字段 抽象方法:可以定义抽象方法 非抽象方法:可以定义非抽象方法 接口(interface): 继承:可以extends多个interface& 可以implements多个interface 字段:不能定义实例字段 抽象方法:可以定义抽象方法 非抽象方法:可以定义default方法
1、面向对象特性:重载重写、继承、多态、反射
2、常见关键字 final、static、abstract、finalize、transient、native
3、StringBuffer、StringBuilder 和 String、字符常量池
4、六大设计原则、常见的设计模式(代理、工厂、单例、装饰者、观察者)
5、异常、常见的异常类
6、序列化
7、深拷贝和浅拷贝、值传递和引用传递
8、抽象类和接口
9、基本类型的默认值和取值范围以及字节数
字段 field、 构造器 constructor、 属性(properties)(类属性、实例属性)、变量 (variable)、方法(method)、内部类(inner class) 有什么区别?
属性 :修饰符 数据类型 (属性类型)属性名 = 初始化值 ;
- Java中的属性(property),通常可以理解为get、set方法、is方法。
- 属性实现了字段的封装,属性有get、set 方法来控制字段,供外部访问
Java中的属性,其实是相对于JavaBean来说的。所以在Java中,正确的说法应该是JavaBean中有XXX属性,Java类中有OOO字段或成员变量。属性的英文翻译是property
BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
System.out.println(propertyDescriptor.getName());
}
复制代码
如上代码就会输出UserInfo类对应的JavaBean的所有属性名
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {
//常量
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
//字段
private String id;
private String displayName;
private ApplicationContext parent;
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors;
private long startupDate;
private boolean active;
private boolean closed;
private final Object activeMonitor;
private final Object startupShutdownMonitor;
private Thread shutdownHook;
private ResourcePatternResolver resourcePatternResolver;
private LifecycleProcessor lifecycleProcessor;
private MessageSource messageSource;
private ApplicationEventMulticaster applicationEventMulticaster;
private Set<ApplicationListener<?>> applicationListeners;
private ConfigurableEnvironment environment;
//属性 对应的方法
public void setId(String id) {
this.id = id;
}
//属性 对应的方法
public String getId() {
return this.id;
}
//属性 对应的方法
public void setDisplayName(String displayName) {
Assert.hasLength(displayName, "Display name must not be empty");
this.displayName = displayName;
}
//属性 对应的方法
public String getDisplayName() {
return this.displayName;
}
//属性 对应的方法
public boolean isRunning() {
return this.getLifecycleProcessor().isRunning();
}
//属性 对应的方法
@Override
public String getApplicationName() {
return "";
}
//属性 对应的方法
/**
* Return the list of statically specified ApplicationListeners.(返回静态指定的applicationlistener的列表。)
*/
public Collection<ApplicationListener<?>> getApplicationListeners() {
return this.applicationListeners;
}
//方法
public void start() {
this.getLifecycleProcessor().start();
this.publishEvent(new ContextStartedEvent(this));
}
//方法
public void stop() {
this.getLifecycleProcessor().stop();
this.publishEvent(new ContextStoppedEvent(this));
}
复制代码
字段
- 字段(field),通常叫做“类成员”,或 "类成员变量”,有时也叫“域”,理解为“数据成员”,用来承载数据的。
- Java中字段的含义就是Java类中定义的成员变量,可以通过Java的反射机制获取所有的字段名,
Class#getFields()
方法或者Class#getDeclaredFields()
方法,看出field其实就是字段的意思。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {
//////常量const
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected final Log logger;
///////字段 field
private String id;
private String displayName;
private ApplicationContext parent;
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors;
private long startupDate;
private boolean active;
private boolean closed;
private final Object activeMonitor;
private final Object startupShutdownMonitor;
private Thread shutdownHook;
private ResourcePatternResolver resourcePatternResolver;
private LifecycleProcessor lifecycleProcessor;
private MessageSource messageSource;
private ApplicationEventMulticaster applicationEventMulticaster;
private Set<ApplicationListener<?>> applicationListeners;
private ConfigurableEnvironment environment;
复制代码
方法 (method,函数)
变量 (接口里面为常量)
- 在方法体外,类体内声明的变量称为成员变量。
- 在方法体内部声明的变量称为局部变量。
属性和字段区别:
Java中的属性(property),通常可以理解为get和set方法。更形象的说就是:属性是对字段的封装,供外部访问。 而字段(field),通常叫做“类成员”,或 "类成员变量”,有时也叫“域”,理解为“数据成员”,用来承载数据的。
JavaBean的属性名其实就是Java类中定义的setter或者getter方法名,去掉set或者get或者is得到的字符串,判断首字母是否是小写,如是,则该字符串就是属性名,否则再判断第二个字母是否是大写,如是,则该字符串就是属性名,否则将首字母小写得到的名称就是属性名,比如getDizhi()
方法属性名就是dizhi
,getdizhi()
方法属性名也是dizhi
,getdIzhi()
方法属性名就是dIzhi
,getDIzhi()
方法属性名就是DIzhi
,其中bool类型的属性的get方法名不是以get开头,而是以is开头。
对于只有get或者只有set方法的属性,我们就说他是只读或只写属性。之所以规定Java的字段定义不准以is开头且首两个字母要么都大写要么都小写,就是为了让JavaBean的属性名与字段名一致。