static
用static修饰的成员变量称为静态变量(类变量),若无static修饰,则是实例变量。静态变量或类变量是一种全局变量,它属于某个类,不属于某个对象实例,是在各对象实例间共享。如果想访问静态变量可以直接通过类名来访问,可以不通过实例化访问它们。而实例变量就必须通过对象实例来访问它们。
同样,static修饰的成员方法称为静态方法(类方法),调用静态方法可以通过类名来调用,即不用实例化即可调用它们。
class Example05_2{
public static int add(int x,int y){
return x+y;
}
}
class Example05_2Demo{
public void method(){
int a=1;
int b=2;
int c= Example05_2.add(a,b);
}
}
静态初始化块
类变量的初始化也可以通过静态初始化块来进行。静态初始化块是一个块语句,代码放置在一对大括号内,大括号前用关键字static修饰。 一个类中可以定义一个或多个静态初始化块。静态初始化块会在加载类时调用而且只被调用一次。
class Example05_4 {
static int i = 5;
static int j = 6;
static int k;
static void method() {
System.out.println(″k=″ + k);
}
static {
if(i * 5 >= j * 4) k = 10;
}
public static void main(String args[]) {
Example05_4.method();
}
}
(final)类
final在类之前,表示该类不能被继承,即final类不能作为父类,任何final类中的方法自动成为final方法,一个类不能同时用abstract和final修饰;
final在方法之前,防止该方法被覆盖,final方法不能被重写,因此,如果你在子类中有一个同样签名的方法的话,你会得到一个编译时错误 final在变量之前,定义一个常量,一个final变量的值不能被改变,并且必须在一定的时刻赋值。
final class Base{
public void amethod(){
System.out.println(“amehthod”);
}
}
public class Fin {
public static void main(String[] args){
Base b=new Base();
b.amethod();
}
}
抽象方法与抽象类
Java中可以定义一些不含方法体的方法,它的方法体的实现交给该类的子类根据自己的情况去实现,这样的方法就是abstract修饰符修饰的抽象方法,包含抽象方法的类就叫做抽象类,也要用abstract修饰符修饰。
用abstract来修饰一个方法时,该方法叫做抽象方法。形式如下: abstract [修饰符] <返回类型> 方法名称([参数表]);
抽象方法并不提供实现,即方法名称后面只有小括号而没有大括号的方法实现。包含抽象方法的类必须声明为抽象类。抽象超类的所有具体子类都必须为超类的抽象方法提供具体实现
抽象类通常包含一个或多个抽象方法(静态方法不能为抽象方法)。 抽象类必须被继承,抽象方法必须被重写; 抽象类不能被直接实例化。因此,它一般作为其他类的超类,使用抽象超类来声明变量,用以保存抽象类所派生的任何具体类的对象的引用。程序通常使用这种变量来多态地操作子类对象。与final类正好相反;
abstract class A {
int x;
abstract int m1();
abstract int m2();
}
abstract class B extends A {
int y;
int m1() {
return x + y;
}
}
class C extends B {
int z;
int m2() {
return x + y + z;
}
}
接口(interface)
在java中,接口是由一些常量和抽象方法所组成,接口中也只能包含这两种东西,一个接口的声明跟类的声明是一样的,只不过把class关键字换成了interface
interface A{
void method1(int i);
void method2(int j);
}
实现接口我们使用implements关键字。在子类中可以使用接口中定义的常量,而且必须实现接口中定义的所有方法,否则子类就变为抽象类了。
interfac Sittable
{
void sit();
}
interface Lie
{
void sleep();
}
interface HealthCare
{
void massage();
}
class Chair implements Sittable
{
public void sit(){};
}
/*interface Sofa extends Sittable,Lie //接口可以实现多重继承,用逗号相隔。
{
}*/
class Sofa extends Chair implements Lie,HealthCare//一个类既可以从父类中继承同时又可以实现多个接口。
{
public void sleep(){};
public void massage(){};
}
内部类
Inner Class按照字面意思就是内部类的意思,简单说就是嵌套在另一个类中定义的类就是内部类(Inner Classes)。包含内部类的类叫做外部类。
可以让程序设计中逻辑上相关的类结合在一起。有些类必须要伴随另一个类存在才有意义,如果两者分开,可能在类的管理上比较麻烦,所以我们可以把这样的类写成一个Inner Class。 Inner Class可以直接访问外部类的成员。因为Inner Class在外部类中,理所当然可以访问任何的成员,包括声明为private的成员。
在外部类中访问静态内部类成员
class Outer //这是一个外部类
{
int outer_x = 100; //外部类成员
class Inner //这是一个内部类
{
void display() //内部类成员
{
System.out.println("display: outer_x = " + outer_x);
}
}
}
在外部类外访问静态内部类成员
class Outer {
class Inner {
int i = 50;
int j = 100;
}
}
public class Test {
public static void main(String[] args) {
Outer.Inner on1 = new Outer().new Inner();
Outer ot = new Outer();
Outer.Inner on2 = ot.new Inner();
System.out.println("内部类中的变量i的值为:" + on1.i);
System.out.println("内部类中的变量j的值为:" + on2.j);
}
}
public class OuterClass {
private int outerVar = 10;
class InnerClass {
void display() {
System.out.println("Outer variable: " + outerVar);
}
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.display();
}
}
public class OuterClass {
private static int staticVar = 20;
static class StaticNestedClass {
void display() {
System.out.println("Static variable: " + staticVar);
}
}
public static void main(String[] args) {
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
nested.display();
}
}
public class OuterClass {
void outerMethod() {
class LocalInner {
void display() {
System.out.println("Inside local inner class.");
}
}
LocalInner localInner = new LocalInner();
localInner.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.outerMethod();
}
}
public interface Greeting {
void greet();
}
public class OuterClass {
void displayGreeting() {
Greeting greet = new Greeting() {
@Override
public void greet() {
System.out.println("Hello, anonymous inner class!");
}
};
greet.greet();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.displayGreeting();
}
}
匿名内部类是 Java 中的一个特殊概念,它允许你在创建一个类的实例的同时定义该类的一个子类或实现其接口。这种内部类是没有显式类名的,因此称为“匿名”内部类。
自动装箱与拆箱
装箱
int i = 10;
Integer integerObj = i; // 自动装箱,编译器会自动将基本类型 int 转换为 Integer 对象
拆箱
Integer integerObj = 20;
int i = integerObj; // 自动拆箱,编译器会自动从 Integer 对象中提取 int 值
比较操作:在使用 ==
进行比较时,自动拆箱可能会导致预期外的结果,因为对于包装类对象,==
比较的是对象引用,而不是值。对于基于 int
值范围的自动装箱,Java 会使用一个内部的整数缓存池,范围是 -128
到 127
。因此,当你比较两个 Integer
对象的值在这个范围内时,它们通常会引用相同的对象,导致 ==
操作返回 true
。
public class AutoPackingTest
{
public static void main(String[] args)
{
Integer A = 3;
int a = A;
System.out.println(a); // 输出:3,因为A被自动拆箱为int类型的值并赋给了a
Integer A1 = 3;
System.out.println(A == A1); // 输出:true,因为Java在编译时会自动将A和A1装箱为Integer对象,对于值较小的整数,Java会重用同一个对象。
A = 129;
A1 = 129;
System.out.println(A == A1); // 输出:false,因为值为129的Integer对象不会被重用。每次都会创建一个新的对象,所以它们的引用不同。
}
}
枚举
使用 enum
关键字来定义枚举类型。例如,定义一个简单的枚举类型表示星期:
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumTest {
public static void main(String[] args) {
// 创建枚举数组
Day[] days = new Day[] { Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY,
Day.THURSDAY, Day.FRIDAY, Day.SATURDAY, Day.SUNDAY };
// 打印枚举常量的序号以及枚举值
for (int i = 0; i < days.length; i++) {
System.out.println("day[" + days[i].ordinal() + "]:"
+ days[i].name());
}
// 通过compareTo方法比较,实际上其内部是通过ordinal()值比较的
System.out.println("day[1] VS day[2]:" + days[1].compareTo(days[2]));
}
}
访问枚举常量: 你可以像访问类的静态变量那样访问枚举常量:
Day today = Day.MONDAY;
System.out.println(today); // 输出: MONDAY
注解
Java 的注解(Annotation)是从 Java 5 开始引入的一个特性,它为代码提供了元数据,使得我们可以在代码中嵌入有关代码的信息,而这些信息可以被编译器或工具进行解析和使用。注解在许多地方都有应用,如代码的编译、运行时的处理以及在开发工具中。
定义注解:
使用 @interface
关键字来定义一个注解。
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时可以被反射访问
@Target(ElementType.METHOD) // 表示该注解可以用于方法上
public @interface MyAnnotation {
String value() default "default value";
int number() default 0;
}
内置注解: Java 本身提供了一些内置的注解,如 @Override
、@Deprecated
、@SuppressWarnings
等。这些注解有特定的用途。
使用注解:
在代码中使用定义好的注解。
public class OverrideTest {
String name;
@Override
public String toString(){//不报错,OverrideTest的父类Object有toString方法
return name;
}
@Override
public String fromString(){//报错,OverrideTest的父类Object没有fromString方法
return name;
}
}
@Deprecated 当我们希望编译器知道某一方法不建议使用时,我们应该使用这个注解。Java在javadoc 中推荐使用该注解,我们应该提供为什么该方法不推荐使用以及替代的方法。
@SuppressWarings 这个是告诉编译器忽略特定的警告信息
Lambda表达式
它可以使用一种简洁的方式来创建只有一个抽象方法的接口(函数式接口)的实例,它允许把函数作为一个方法的参数(函数作为参数传递进方法中)
lambda 表达式的语法格式如下:
(Parameters) -> Expression 或
(Parameters) ->{ Statements; }
前面介绍的匿名内部类的例子中,采用new对象创建匿名内部类并完成对方法的访问。
InnerFather nf=new InnerFather() //创建匿名内部类
{
public void method()
{
System.out.println(val); //访问局部变量
}
};
以上程序采用Lambda表达式的简化写法如下:
InnerFather nf = ( ) ->System.out.println(val);
每一个Lambda表达式都对应一个类型,通常是接口类型。而每一个函数式接口类型的Lambda表达式都会被匹配到这个抽象方法。所以我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,即Lambda表达式的类型必须是“函数式接口”。
package sample;
interface Cook{
void makeFood();
}
public class LambdaExpressionTest {
public static void main(String[] args) {
//内部类方法
invokeCook(new Cook() {
@Override
public void makeFood() {
System.out.println("享用美食!");
}
});
//使用lambda表达式
invokeCook(()->{
System.out.println("享用美食!");
});
}
public static void invokeCook(Cook cook){
cook.makeFood();
}
}