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();
 
复制代码
  • 静态方法是不允许被重写。

image.png

  • 如果一个抽象类没有字段,所有方法全部都是[抽象方法]就可以把该抽象类改写为接口(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其实就是字段的意思。

image.png

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,函数)

变量 (接口里面为常量)

  • 在方法体外,类体内声明的变量称为成员变量。
  • 在方法体内部声明的变量称为局部变量。

image.png

属性和字段区别:

Java中的属性(property),通常可以理解为get和set方法。更形象的说就是:属性是对字段的封装,供外部访问。 而字段(field),通常叫做“类成员”,或 "类成员变量”,有时也叫“域”,理解为“数据成员”,用来承载数据的。

JavaBean的属性名其实就是Java类中定义的setter或者getter方法名,去掉set或者get或者is得到的字符串,判断首字母是否是小写,如是,则该字符串就是属性名,否则再判断第二个字母是否是大写,如是,则该字符串就是属性名,否则将首字母小写得到的名称就是属性名,比如getDizhi()方法属性名就是dizhigetdizhi()方法属性名也是dizhigetdIzhi()方法属性名就是dIzhi,getDIzhi()方法属性名就是DIzhi,其中bool类型的属性的get方法名不是以get开头,而是以is开头。

对于只有get或者只有set方法的属性,我们就说他是只读或只写属性。之所以规定Java的字段定义不准以is开头且首两个字母要么都大写要么都小写,就是为了让JavaBean的属性名与字段名一致。

来源:https://juejin.cn/post/7167723266474246180
posted @ 2022-12-18 23:38  程序员小明1024  阅读(148)  评论(0编辑  收藏  举报