android--java必会问题

final 修饰什么?

Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。
  1.修饰类
  当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
  2.修饰方法
  下面这段话摘自《Java编程思想》第四版第143页:
  “使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
  因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。
  注:类的private方法会隐式地被指定为final方法。
  3.修饰变量
  修饰变量是final用得最多的地方,首先了解一下final变量的基本语法:
  对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
一句话:final可以修饰:类 变量 方法;final修饰的类不能被继承;final修饰的方法不能被重写;final修饰的变量是一个常量,只能背赋值一次。

static关键字能修饰什么?

static详解:https://www.cnblogs.com/dolphin0520/p/10651845.html
static关键字是Java中常用的关键字之一,可能最常用的就是修饰变量和方法了,但是仅仅知道这些还远远不够。问题虽然很小,但是却反映了对Java的了解程度。

static修饰变量和方法

static可以修饰变量,这个变量属于类本身,不需要创建实例就可以直接获取到值。
static可以修饰方法,这个方法属于类本身,同样,不要创建实例就可以通过类调用。

需要了解的是,static修饰的变量或方法属于类的静态资源,是所有实例共享的,另外静态方法内部是不能访问非静态方法的,因为静态资源是在类加载的时候就建立好的,而类加载时非静态方法需要类new的时候才能创建,一前一后的顺序所以导致了Java静态方法不能访问非静态资源的结果,当然反之肯定是可以的了。

static修饰代码块

static修饰的代码块是静态代码块,也具有静态的特点,属于类本身,在加载时只需要加载一次,也就是说,如果加载过这个代码块,就不会再加载了。

static修饰类
static修饰类只有一种情况,那就是这个类属于静态内部类,接触过Android开发的话可能遇见过很多这样的静态内部类,如WindowManager.LayoutParams类,LayoutParams就是WindowManager类下的静态内部类,它的源码如下所示:

public interface WindowManager extends ViewManager {
    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
        //内部实现
    }
}

普通类是不允许声明为静态的,只有内部类才可以。

被static修饰的内部类可以直接作为一个普通类来使用,而不需先实例一个外部类。

public class OuterClass {  

    public static class InnerClass {  

        InnerClass(){  
            System.out.println("===== 我是一个内部类'InnerClass' =====");  
        }  
    }  
}  
public class TestStaticClass {  

    public static void main(String[] args) {  

         // 不需要先new一个OutClass的对象  
        OuterClass.InnerClass inner = new OuterClass.InnerClass();  
    }  
}  

如果没有用static修饰InterClass,则只能按如下方式调用:

public class OuterClass {  

    public class InnerClass{  

        InnerClass(){  
            System.out.println("===== 我是一个内部类'InnerClass' =====");   
        }  
    }  
}  
public class TestStaticClass {  

    public static void main(String[] args) {  

        // 需要先new一个OuterClass的对象outer
        // 然后通过outer.new生成内部类的对象
        OuterClass outer = new OuterClass();  
        OuterClass.InnerClass inner = outer.new InnerClass();  
    }  
}  

import static
这个算是比较冷门的,但是知识不怕多,import static是JDK1.5之后的新特性,这两个关键字连用可以指定导入某个类中的指定静态资源。

import static java.lang.Math.*;

 public class A
{
     public static void main(String[] args)
     {
         System.out.println(sin(2.2));
   }
}

不需要再加Math.sin()的Math了,还是很方便的,但是可读性不高,不建议这样写。

修饰内部类和外部类区别

Java内部类详解:https://www.cnblogs.com/dolphin0520/p/3811445.html

java 内部类和静态内部类的区别:https://www.cnblogs.com/aademeng/articles/6192954.html
内部类和外部类的区别和联系:https://www.cnblogs.com/NYfor2018/p/9466476.html

String s = ‘abc’ 是在哪块内存中存储

答:方法区的常量池

String s=“abc” 和 String s1=new String(“abc”)内存分析

String s=”abc”

s是栈内变量,它的内存保存的是常量池的常量字符串对象对象”abc”的地址。常量池中的每个值只有一份。String s2 = “abc”;

s和s2两个变量指向的是同一个地址,因此s==s2结果为true

String s1=new String(“abc”);
s1是栈内变量,它的内存保存的是堆中的new String对象的地址,new String在堆中生成对象,并用常量池的字符串对象”abc”初始化堆中的对象,所以堆中的对象的内存的内容和常量池对象的内存的内容一样,但是是不同的两个对象

因此s==s1的结果是false。==比较的是两对象的引用,因此结果为false.

s.equals(s1)的结果是true,因为String的equals方法比较的是对象的内容。

String s = “abc”到底做了啥

作为开发人员在类里面定义String变量几乎是家常便饭,亦或是日常了,照理说String是个对象,为什么我们定义的时候不是直接 new String(“abc”);

而是直接写了对象内容,难道不觉得有点诡异吗?

String s1 = “abc”;

String s2 = “abc”;

String s3 = new String(“abc”);

System.out.println("s1 = s2? " + (s1 == s2)); //true

System.out.println("s1 = s3? " + (s1 == s3)); //false

怎么去理解上面的结果,大家知道字面量赋值是在常量池,常量池其实是一张表:

常量池(Constant Pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。JVM虚拟机为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(String,Integer和 Floating point常量)和对其他类型,字段和方法的符号引用。对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。

1.Strings = “abc”;
创建过程分析:在class文件被JVM装载到内存中,JVM会创建一块String Pool(String缓冲池)。当执行String s = “abc”;时,JVM首先在String Pool中查看是否存在字符串对象“abc”(如何查看呢?用equals()方法判断),如果已存在该对象,则不用创建新的字符串对象“abc”,而直接使用String Pool中已存在的对象“abc”,然后将引用s指向该对象;如果不存在该对象,则先在String Pool中创建一个新的字符串对象“abc”,然后将引用s指向String Pool中创建的新对象。
注意:使用“字符串常量”引号创建的字符串对象时,在编译期就已经确定将该对象存储到String Pool中了。因此,String s = “abc”只会在编译期,在String Pool中创建一个对象。

2.new String(“abc”);

将会在堆中创建对象,查看下String构造方法源码

private final char value[];

public String(String original) {
  this.value = original.value;
  this.hash = original.hash;
}

很明显在堆中String其实是char数组维护一组数据,前者是表后者是数组,结构不一样,地址存放不一样,引用自然不一样,虽然内容是一样!

重载和重写

https://www.runoob.com/java/java-override-overload.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值