JAVA基础之包装类,static,final,abstract ,接口 和 内部类
Posted 蜡笔大新001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础之包装类,static,final,abstract ,接口 和 内部类相关的知识,希望对你有一定的参考价值。
包装类:
自jdk5之后,java就提供了自动装箱与自动拆箱功能,大大简化了基本类型与其包装类对象之间的转换过程,当然装换过程中要注意类型的匹配。
public class IntAndInteger { public static void main(String[] args) { //自动装箱 Integer intObj = 5; Integer intObjj = 5; //自动拆箱 int a = intObj; //包装类实现基本变量与字符串的转换 String str = "123"; //使用静态方法转换 int b = Integer.parseInt(str); //使用构造器转换 int c = new Integer(str); //多个重载的valueOf()方法,把基本类型转换为字符串 String s = String.valueOf(b); String boo = String.valueOf(false); //基本类型或包装类加上“”,会自动转换为string类型 String ss = a+""; String sss = intObj+""; //包装类实例可以与基本数值类型比较大小,用的是其包装的数值 Integer i = new Integer(6); System.out.println(i > 5); //两个包装类的实例进行比较,只有两个包装类执行同一个对象,才相等 System.out.println(intObj == intObjj); //true,都指向常量池中的5 System.out.println(intObj == i);//false /* * 看下一个自动装箱例子,查看Integer的源码,将会看到如下代码: static final Integer[] cache = new Integer[256]; static { for(int i=0;i<cache.length;i++) cache[i] = new Integer(i-128); } 从上面代码中可以看出,Integer把-128~127之间的整数自动装箱成Integer之后,存到一个一个数组中, 所以每次装箱的整数在-128~127之间都是直接指向数组元素,而这个范围之外的整数自动装箱都会新创建一个Integer实例 */ Integer a1 = 2; Integer a2 = 2; System.out.println(a1 == a2); //true Integer b1 = 128; Integer b2 = 128; System.out.println(b1 == b2); //false //java7为所有的包装类都提供了静态的compare方法,比较基本类型的大小 System.out.println(Boolean.compare(false, true)); //-1 System.out.println(intObj.equals(a)); //true } }
==比较数值类型的基本变量(不一定要求类型完全相同),只要变量的值相等,就返回true; ==比较引用类型变量,只有两个变量指向同一个对象时,才返回true ,==不能用于比较两个类型上没有父子关系的两个对象; equals()是Object的方法,一般子类都要重写该方法,其目的是比较两个引用变量指向的对象的内容是否相同,当然具体的判断条件由编程者自己规定。有些累已经重写了该方法,如String类,用于比较两个字符串的内容是否相同
常量池专门用于管理在编译时被确定并保存在.class文件中的一些数据 “abc” 与 new String("abc")(实际创建两个String对象),常量池保证相同的字符串直接量只有一个
static:
/* * 1. static修饰的成员属于类成员,包括类变量,类方法,静态初始化块,内部类,static不能修饰构造器 * 2. 静态变量,同一个类的所有实例共享同一块内存区 * 3. 类方法,即使实例为null,依然可以访问类方法或变量 * 4. 类成员(类方法,初始化块,内部类)不能访问实例成员(变量,方法,初始化块,内部类),反之可以 * 5. 不能在方法中声明静态变量 */ public class ClassNumber { private static void test() { System.out.println("测试"); } public static void main(String[] args) { ClassNumber classNumber = null; //=null,先进行初始化 classNumber.test(); } }
final:
final修饰变量
/* * 1.final修饰成员变量,一旦获得了初始值,就不能再被重新赋值,final修饰类变量,只能在声明时或者静态代码块之一为其赋值; * final修饰实例变量,可以在声明时,非静态代码块,构造器三者之一为变量赋值 * final修饰的变量必须由程序员显示的指定初始值,否则编译出错 */ /* * 2.final修饰局部变量 * final修饰局部变量,要么在声明时初始化,要么在之后初始化一次 * final修饰形参,调用该方法时会进行初始化,所有方法中不能对其进行赋值 * 3.final修饰基本类型的变量时,需保证变量的值不能发生改变,修饰引用类型变量时,只需保证变量指向的地址空间 * 不发生变化就可以,它指向的对象可以随意改变 */ /* * 4.可执行宏替换的final变量,用final修饰的变量,无论是类变量,实例变量,还是局部变量 * 只要满足以下三个条件就可以当做直接量来看,进行宏替换,编译时把用到该变量的所有地方替换成对应值 * 1>使用final变量修饰 * 2>声明时指定了初始值 * 3>变量的值可以在编译时确定下来 * 注:除了为final变量赋值为直接量之外,如果被赋的表达式是最基本的算术表达式或字符串直接量连接运算, * 没有使用普通变量,调用方法,java编译器同样会把这种变量作为“宏变量” */ public class FinalTest { public static int h = 0; public static void main(String[] args) { final String str = "好人"; //str = "大好人"; 错误 final int a = 5; System.out.println(a); //对程序来说变量a根本不存在,相当于执行System.out.println(5) /* * 宏变量 */ final int b = 2 ; //宏 final String str1 = "Linux程序设计"; //宏 final String str2 = "Linux"+"程序设计"; //宏 String str3 = "程序设计"; //普通变量 String str4 = "Linux" + str3 ; //使用普通变量,不是宏 System.out.println(str1 == str2); //true System.out.println(str1 == str4); //false } public void test(final int a) { //a = 5; 不能再次赋值 } }
final修饰方法:
/* * 1.子类不能重写父类中使用final修饰的方法,否则编译出错 * 2.当父类中的方法使用private final修饰的时候,该方法只在类中可见,子类并不能继承到该方法 * 所以完全可以在子类中再次定义一个与其返回值,方法名,参数完全相同的方法 * 3.final修饰的方法只是不能被重写,但是可以被重载 */ public class FinalMethodTest { public final void test(){} private final void test1(){} } class ChildTest extends FinalMethodTest { //public void test(){} 编译出错 public void test1(){} //不出错 public void test(int a){}; //可以 }
final修饰类:
/* * 1.使用final修饰的类不可以有子类 * 2.不可变类:即创建了该类的实例后,该实例的实例变量不可改变,8个包装类与String都是不可变类 * 3.自定义不可变类遵循的原则: * 1>使用private final 修饰成员变量 * 2>提供带参数的构造器,用于根据传入的参数来初始化成员变量 * 3>仅为变量提供get方法,我无需提供set方法,因为普通方法无法改变final变量 * 4>有需要的话重写equals()和hashCode()方法 * 下面创建一个不可变类,不可变类的实例一直处在初始化状态,对其的控制会变的简单 */ public class FinalClassTest { private final String detail; private final String post; public FinalClassTest() { this.detail=""; this.post=""; } public FinalClassTest(String detail,String post) { this.detail=detail; this.post=post; } public String getDetail() { return detail; } public String getPost() { return post; } public boolean equals(Object obj) { if(obj == this) { return true; } if(obj!=null && obj.getClass() == FinalClassTest.class) { FinalClassTest object = (FinalClassTest)obj; if(this.getDetail().equals(object.getDetail()) && this.getPost().equals(object.getPost())) return true; } return false; } public int hashCode() { return this.getDetail().hashCode()+this.getPost().hashCode()*11; } }
/* * 设计具有其他类的引用的不可变类 */ class Name { private String firstName; private String lastName; public Name(){} public Name(String firstName,String lastName) { this.firstName=firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } } public class FinalClassTest2 { private final Name name; //因为name对象是可以改变的,这与设计不可变类初衷相违背 public FinalClassTest2(Name name) { this.name=new Name(name.getFirstName(),name.getLastName()); //使用不同的引用 } public Name getName() { return name; } public static void main(String[] args) { Name name = new Name("孙","悟空"); FinalClassTest2 f = new FinalClassTest2(name); name.setFirstName("猪"); System.out.println(f.getName().getFirstName()); //孙 不会被改变 达到不可变类的效果 } }
abstract:
package abstractpack; /* * 1.抽象类抽象方法的规则 * 1>抽象类的抽象方法都要用abstract关键字来修饰,包含抽象方法的类一定是抽象类,抽象类可以不包含抽象方法 * 2>抽象类不能被实例化,不能使用new关键字来创建抽象类的对象,即使抽象类不包含抽象方法 * 3>和普通类一样,抽象类中可以声明成员变量,方法,构造器,初始化块,内部类,抽象类的构造器不是用来创建实例,而是供子类调用 * 4>只要类中包含抽象方法,包括自己定义的抽象方法,没有完全实现父类或接口中的抽象方法,则该类必须声明为抽象类 * 2.final和abstract永远不能同时使用 * 3.abstract不能修饰变量,局部变量,构造器 * 4.abstract和static不能同时修饰一个方法,但是可以同时修饰内部类 * 5.abstract方法不能为private权限 */ /* * 模板模式: * 1.抽象父类只定义需要使用的某些方法,把不能实现的部分抽象成抽象方法,交给子类去实现 * 2.父类中可能包含调用其他方法的方法,被调用的方法可能需要具体的子类去实现,见下例: */ class father {} abstract class SpeedMeter extends father //可以继承普通类 { private double turnRate; public SpeedMeter() { } public abstract double getRadius(); public void setTurnRate(double turnRate) { this.turnRate = turnRate; } public double getSpeed() { return Math.PI*2*getRadius()*turnRate; //调用需要子类实现的抽象方法 } } public class CarSpeedMeter extends SpeedMeter { public double getRadius() { return 2.0; } public static void main(String[] args) //入口方法必须放在public修饰的类里!!! { CarSpeedMeter speed = new CarSpeedMeter(); speed.setTurnRate(3.0); System.out.println(speed.getSpeed()); } }
interface:
package interfacepack; /* * 1.因为接口定义的是一种规范,所有接口里不能包含构造器和初始化块。接口里可以包含变量(public static final,在定义是指定默认值), * 方法(public abstract抽象方法,static类方法,default默认方法,java8以上才支持类方法默认方法,必须由方法实现),public static内部类(枚举,内部接口) * 2.接口里定义的是多个类公共的规范,所以所有成员都用public修饰 */ /* * 接口和抽象类: * 共同点:1.都不能被实例化 * 2.都可以包含抽象方法 * 不同点: * 设计目的:接口体现的是一种规范。对于接口的实现者而言,接口规定了实现者必须向外界提供哪些服务,对于接口的调用者而言,它规定了调用者可以得到哪些服务,以及怎样得到 * 当在一个程序中使用接口时,它是多个模块之间耦合的标准;当在多个应用程序之间使用接口时,它是多个程序之间通信标准,一个系统中的接口不应该经常改变 * 抽象类体现的是一种模板式的设计思想,可以把它看成中间产品,防止子类设计的随意性 * 用法上的差别: * 1>不能为普通方法提供方法实现,只能是抽象方法,默认方法,类方法,而抽象方法可以 * 2>不能定义普通成员,只能是静态常量 * 3>不能包含构造器 * 4>不能包含初始化块 * 5>一个类可以实现多个接口,但是只能继承一个抽象类 * */ public interface InterfaceTest { int Max_mine = 50 ; //默认使用public static final修饰,需在定义时初始化 void out(); //普通方法默认使用public abstract修饰 default void print(Object obj) //默认方法,使用default修饰,必须提供方法体,不能用static修饰 { System.out.println(obj); } static void write(Object obj) //类方法,使用static修饰,必须提供方法体,不能用default修饰,可由接口直接调用 { System.out.println(2); } }
面向接口编程:
package interfacepack; /* * 面向接口编程 * 1.简单工程模式: * 假设需要为Computer类组装一个输出设备,这时,我们让computer类耦合输出设备的父接口Output,以后不论电脑需要的输出设备 * 怎样改变,电脑类的代码都不需要改变.电脑类不需要产生输出设备的实例,而交给工厂类来完成 * 这样即可把所有生产Output对象的逻辑都集中在OutputFactory中,而所需要使用Output对象的类只需要与接口耦合,而不是 * 与具体的实现类耦合 */ public class Computer { private Output output; public Computer(Output output) { this.output = output; } //调用输出设备的方法... } //定义一个工厂类,生产输出设备 class Factory { public Output getOutput() { return new Printer(); //return new BetterPrinter(); } } interface Output { //一些作为输出设备需要提供的方法 //... } class Printer implements Output { //实现接口中定义的抽象方法... } class BetterPrinter implements Output { //实现接口中定义的抽象方法... } /* * 2.命令模式:假设某个方法要完成某项功能,但是这个功能的实现必须等到执行时才能确定,这时可以把命令作为参数传递进去 * 假设需要对数组进行操作 */ //定义Command接口来封装处理行为 interface Command { void process(int[] target); } //处理数组的类,可以在调用该类的process方法处理数组的时候,动态的传入Command接口的不同的实现类对象 //以实现对数组的不同类型的操作 public class ProcessArray { public void process(int[] target,Command cmd) { cmd.process(target); }
内部类:
成员内部类
package innerclasspack; /* * 1.成员内部类是一种与成员变量,成员方法,初始化块相似的类成员,而局部内部类和匿名内部类不是类成员 * 2.外部类的上一级程序单元是包,所以他只有两个作用域,一个是包(缺省),一个是公开(public),而内部类的外层是外部类,它有4个作用域, * 类内(private),包(缺省),父子类(protected),公开(public) * 3.非静态内部类: * 1>非静态内部类可以直接访问外部类中的私有成员,在其内部保存了一个对外部类对象的引用 * 2>如果外部类想要调用非静态内部类中的实例成员(包括private),则必须先创建内部类的对象,因为外部类的对象存在时,不一定存在内部类的对象,而内部类的对象存在时, * 外部类的对象一定存在 * 3>不允许在外部类的静态成员中直接使用非静态内部类,包括创建对象,使用变量 * 4>java不允许在非静态内部类中定义静态成员,包括变量,方法,静态初始化块 * 4.静态内部类: * 1>static关键字的作用是把类的成员变成类相关,而不是实例相关,因此static关键字不能修饰外部类,但是可以修饰内部类 * 2>静态内部类既可以包含静态成员,也可以包含非静态成员,静态内部类只能访问外部类的实例成员,即使是静态内部类的实例方法,也不能访问外部类的实例成员 * 因为静态内部类是外部类类相关的,当静态内部类的对象存在时,并一定存在被它寄生的外部类的对象,只持有对外部类的类引用 * 3>静态内部类时外部类的静态成员,所以外部类的所有方法,初始化块都能使用静态内部类创建对象,定义变量。但是依然不能直接访问其内部的成员,可以 * 通过类名或者创建内部类的对象来调用 * 4>接口里定义的内部类只能是public static */ /* * 使用内部类:定义类的主要作用就是定义变量,创建实例,被继承 * 1.在外部类内部使用内部类:与使用普通类没有太大区别,只要注意别在外部类的静态成员中使用非静态内部类 * 2.在外部类外使用非静态内部类: * 1>若想要在外部类之外使用内部类,则不能使用private * 缺省:可以被同一包中的其他类访问 * protected:可以被与外部类处于同一个包中的以及外部类的子类访问 * public:被所有类访问 * 2>创建内部类对象的格式:OuterInstance.new InnerConstructor(),即要先创建外部类的实例,在由其调用内部类的构造方法 * 3>创建内部类的子类时,其子类也需要包含对外部类对象的引用,所以子类的构造方法中应该传入对外部类对象的引用 * 4>非静态把内部类的子类可以是一个外部类,但是需要保存对外部类对象的引用 * 3.在外部类以外使用静态内部类: * 1>创建实例:new OuterClass.InnerConstructor(); * 2>声明子类:class SubStaticClass extends StaticOut.StaticIn{},要使用父类的构造器,外部类像是包空间 * 3>既然内部类时外部类的成员,是否可以定义外部类的子类,重写其内部类成员??答案是不可以,内部类的类名实际是把外部类类名作为命名空间 * 子类外部类,命名空间改变,内部类也不再是同一个内部类,即使类名相同 */ //访问非静态内部类 class Out { class In //同一个包中可以访问 { public In(String name) { System.out.println(name); } } } public class CreateInnerInstance { public static void main(String[] args) { Out.In in = new Out().new In("lee"); //创建实例 } } class SubClass extends Out.In { public SubClass(Out out) //子类包含对外部类对象的引用 { out.super("hello"); } } //访问静态内部类 class StaticOut { static class StaticIn { public StaticIn(String name) { System.out.println(name); } } } public class CreateInnerInstance { public static void main(String[] args) { StaticOut.StaticIn in = new StaticOut.StaticIn("lee"); //创建实例 } } class SubStaticClass extends StaticOut.StaticIn { public SubStaticClass(String name) //使用父类的构造器 { super(name); } }
局部内部类和匿名内部类:
package innerclasspack; /* * 局部内部类: * 1>因为局部内部类不能在方法之外的地方使用,所以不能使用访问控制符和static修饰 * 2>如果需要使用局部内部类定义变量,创建实例,或者派生子类,只能在方法中进行 * 3>编译之后生成三个.class文件:JuBuInnerClass.class , JuBuInnerClass$1InnerBase.class , * JuBuInnerClass$S1ubInneBase.class,数字是 为了区分方法中同名的内部类 * 匿名内部类: * 1>匿名内部类适合那种只需要使用一次的类,创建匿名内部类时会立即创建该类的实例,之后这个类定义立即消失 * 2>语法格式:new 实现接口()|父类构造器(实参){类体},匿名内部类必须实现一个接口或者继承一个类,而且只能是一个。 * 3>匿名内部类不能是抽象类,不能有构造器,可以有初始化块 * 4>当通过实现接口来创建匿名内部类时,其只有一个隐式的无参构造器,所以new关键字后面不能传入参数值;如果通过继承父类来创建内部类, * 其具有与父类相似的构造器,即构造器的形参列表相同。 * 5>在java8之前,java要求被局部内部类和匿名内部类访问的局部变量必须是final类型,java8之后这个限制被取消了,如果局部变量 * 被匿名内部类访问,会自动为其加上final修饰符。 */ //局部内部类 public class JuBuInnerClass { public static void main(String[] args) { class InnerBase { int a; public InnerBase(){} } class SubInneBase extends InnerBase //方法中进行 { int b; } SubInneBase sub = new SubInneBase(); sub.a = 1; sub.b = 2; System.out.println("子类的变量值a:"+sub.a+" b:"+sub.b); } } //匿名内部类 interface Product { public double getPrice(); } public class JuBuInnerClass { public void test(Product p) { System.out.println("商品的价格:"+p.getPrice()); } public static void main(String[] args) { JuBuInnerClass j = new JuBuInnerClass(); j.test(new Product() //商品的价格:11.11 { public double getPrice() { return 11.11; } }); } } //调用局部变量 interface A { void test(); } public class JuBuInnerClass { public static void main(String[] args) { int age = 8; A a = new A() { public void test() { //age = 7; //使用的时候必须按照final变量的使用规则 System.out.println(age); } }; a.test(); //8 } }
这部分是java基础中很重要的部分,也是面试官的最爱,需要熟练掌握。
以上是关于JAVA基础之包装类,static,final,abstract ,接口 和 内部类的主要内容,如果未能解决你的问题,请参考以下文章
一脚踩进java之基础篇19——面向对象 (final,static关键字)
一脚踩进java之基础篇19——面向对象 (final,static关键字)
JAVA零基础小白学习教程之day09-内部类&权限&final&静态