java常用知识点记忆

类的继承与多态

  • 类的继承不支持多重继承
  • 非private 方法才可以被覆盖
  • 覆盖的方法要求,子类中的方法的名字,参数列表,返回类型与父类相同
  • 方法的重载是在一个类中定义方法名字相同,但是参数列表不同的方法
  • 要是在子类中定义了与父类名字相同但是参数列表不同的方法,那么这是属于方法的重载(到时调用的时候会根据参数,进行自动的一个选择),但是要是子类覆盖了父类的方法,在一般情况下,不会调用父类被覆盖的方法(可以用super.方法名来调用)
  • super 关键字,可以调用父类的变量(super.变量名),构造器(super(参数列表)),方法(super.方法名),一般父类中的变量没有被子类的变量覆盖的时候,在子类中是可以直接访问使用的,(方法也一样),变量与方法被覆盖之后要用super 才能调用父类中的变量以及方法
  • 子类是不能继承父类的构造方法的,在子类的构造方法,若没有使用super 来调用父类的构造方法,系统会默认调用,其中this 可以用来调用本类的构造方法,不论,super 还是this 只能出现在构造方法的第一句话,并且只能有一句(this 与super 一共只能出现一次)
  • 封装性通过包以及类以及类的成员访问权限实行封装性
  • 在这里插入图片描述
  • final 来修饰类、方法、变量,final 修饰的类为最终类,不允许被继承,final 修饰的方法不能被覆盖,final 修饰的变量为常值变量,一旦赋值则不能被修改
  • 抽象方法是不能实例化的,但是可以通过实例化该抽象方法的子类来实现其中的抽象方法
  • 抽象方法只有方法的申明,没有方法的实现,抽象方法必须在抽象类中
  • 由于final 类不能被继承,可是抽象类必须被继承,所以final 与abstract 不能在定义类时同时实现
  • 子类对象可以自动转换为父类的对象,但是父类对象要强制转换才能转换为子类对象(要求父类对象是运用子类的构造方法生成的
  • 区别方法的多态与重载与重写(覆盖),静态多态通过方法的重载实现,动态多态通过方法的覆盖实现

接口与Lambda 表达式

  • 接口可以实现多继承
  • 接口用interface 关键字来定义,[public ] interface InterfaceName[extends SuperInterface] ,其中public 表示该接口可以被所有的类继承,否则就只能被同一个包中的类继承
  • 接口可以被作为引用变量的数据类型或者类型转换的结果,与抽象类一样,不能被new 进行实例化
  • 接口是常量、抽象方法、默认方法、静态方法的集合,实现接口,就是实现接口中定义的抽象方法,类实现接口用implements 来实现,若实现多个接口,就用逗号进行分隔。由于接口中的抽象方法只有定义没有实现,要是继承接口的类不是abstract 类型,那么该类就要实现接口中的全部的抽象方法(非abstract 类型的类不能存在abstract 方法
  • 类在实现接口的抽象方法的时候,必须使用与抽象方法完全相同的方法标签,否则只是对方法的重载而不是实现
  • 在接口中,定义抽象方法时就算不加上修饰符,编译时也会自动加上 public abstract ,其中接口中的方法都是public 类的,那么在类中实现方法时,就必须显示使用public 来修饰(否则就缩小了访问控制范围)
  • 接口可以多继承,除了本身定义的常量与方法,子接口将继承超接口的全部的常量与方法
  • 一个类可以同时实现多个接口,但是只能同时继承一个类,一个接口能够继承多个接口
  • 一个类实现多个接口,就要实现每一个接口中的抽象方法,接口中的常量以及默认方法都被实现类继承,但是接口中的静态方法不被继承(可以直接用对象.默认方法名字来调用接口中的默认方法)
  • 接口类型的使用:接口是一种引用类型,任何实现该接口的实例都可以被储存在该接口类型的变量中,当通过接口对象调用某一个方法时,java 运行时系统确定该调用哪个类中的方法.
    例如 AA aa = new DD(); //其中 DD 类实现了 AA 接口,aa 为 AA 接口对象 ,存储了实现AA 接口的变量,但是通过aa 来调用只能调用自身的方法(或者自身继承的方法)
  • 定义在接口中的变量,都会自动加上public 、final 、static 属性,因此它们都是常量,常量的定义可以省略修饰符
    int abc = 100;
    public int abc = 100;
    public final static int abc = 100;//这三行等价
  • 接口中的常量一般都用全部大写,由于接口的多继承,可能会造成常量的冲突,如果常量名不冲突,则子接口可以继承父接口中的常量,如果冲突,则子接口不能继承常量,但是可以在子接口定义一个新的同名常量,常量应该通过接口名来调用
  • 静态方法:在一个类中可以定义静态方法,该静态方法被该类的所有的实例共享
  • 在java 早期的版本,接口中只能有抽象方法,在Java SE 8 开始增加 静态方法与默认方法
  • 在接口中定义静态方法:与接口有关的静态方法可以在接口中定义,用static 关键字,默认的访问修饰符为public ,接口的静态方法的使用用"接口名.方法名()"的形式访问,接口的静态方法不能被子接口所继承,也不能被实现类继承(那就只有"接口名.方法名()"这种使用方法)
  • 默认方法:可以给接口中的任何方法都提供一个默认实现,这称为默认方法(default mothod),默认方法的定义用default 关键字,默认方法的使用要通过引用变量调用默认方法可以被子接口以及实现类继承,但是子接口中要是定义了相同的默认方法,父接口中的默认方法被隐藏
  • 如果实现类继承多个接口,造成默认方法的冲突:可以在实现类中定义冲突默认方法的一个新的实现(另起炉灶),或者委托其中一个接口的默认方法来实现(二选一)
  • 接口小结:常量与静态方法可以说是一伙的,它们都通过接口名来调用,因为它们都是 public static 修饰,但是它们也有不同,就是常量是可以被继承的,但是静态方法是不能被继承的,对于默认方法,其实就是相当于类中的一般方法,而对于抽象方法,由于在接口中定义的抽象方法都是没有方法体的,都要靠实现类来实现,有一个重要点要注意,那就是实现抽象方法时的方法必须是public 类型的
  • java 类库中定义了许多接口,有些接口没有定义任何方法,这些接口被称为标识接口
  • Comparable 接口:要比较两个同类对象的大小可以使用Comparable 中的compareTo ()方法,Comparable接口的定义如下:
    public interface Comparable{
    int compareTo(T other );
    }
  • Comparable 接口是泛型接口,实现该接口的时候,将泛型类型T 替换成一种具体的类型。如果希望一个类的对象能够比较大小,类必须实现Comparable <T> 接口中 的 compareTo() 方法。该方法实现当前对象与参数对象进行比较的功能,返回一个整数值。当调用的对象小于、等于、大于参数对象时,该方法分别会返回负整数、0、正整数。按照该方法比较出的对象顺序称为自然顺序
  • Comparator 接口与Comparable 接口相似,但是Comparator 接口的抽象方法compare 有两个 T 类型的参数,而Comparable 有一个T 类型的参数
  • 匿名内部类:匿名内部类是一种没有显式定义类名称的局部内部类的特殊形式。它通常用于创建一个只需使用一次的简单类或接口的实例。匿名内部类的语法形式相对简洁,通常在创建对象或实现接口时使用
  • Lambda 表达式:lambda表达式是可以传递给方法的一段代码,可以是一个语句,也可以是一个代码块。对于函数体只有一行代码的,可以去除大括号{ }以及return 关键字,由于java 编译器会自动推导出参数的类型,所以还可以省略参数类型的指定。
  • 函数式接口:是指仅包含一个抽象方法的接口,又被称为单抽象方法接口。每一个lambda 表达式都对应一个函数式接口类型。可以将Lambda 表达式看作函数式接口的类的一个实例。默认方法不是抽象方法,所以在函数式接口中可以定义默认方法。可以在定义函数式接口时加上@FunctionInterface 语句,这样,当你定义多于一个抽象方法,编译会报错。
  • 函数式接口之所以十分重要:可以使用Lambda 表达式创建一个与匿名内部类等价的对象
  • Lambda 表达式的语法:使用Lambda 表达式将代码传递给方法,有两种方式指定Lambda 表达式:
    (1)(参数1,参数2,···) -> 表达式;
    (2)(参数1,参数2,···) -> {/代码块/};
    Lambda 表达式是用于实现 接口中的抽象方法的,Lambda 表达式的内容就是对抽象方法的创建,对于接口的默认方法,可以通过接口对象来引用
    Lambda 表达式以参数列表开头(就算没有参数,也要有一个括号),参数用括号定界,然后是一个箭头 -> ,最后是表达式主体。括号中的参数传递给表达式。如果表达式只有一个语句,那么语句块的大括号可以省略。如果参数的类型是可以推导的,则可以省略类型,如果只有一个参数,且该参数的类型可以推导,那么参数括号可以省略。
  • 预定义的函数式接口:
    (1)Function<T,R> 表示带一个参数且返回一个结果的函数,结果类型可以与参数类型不同,需要覆盖 R apply(T)方法
import java.util.function.*;
public class FunctionDemo {
     
     
	public static void main(String[]args) {
     
     
		Function<Integer,Double> milesTokms = (input) -> 1.6*input;
		int miles = 3;
		double kms = milesTokms.apply(miles);
		System.out.printf("%d miles is %3.2f kilometers \n", miles,kms);		
	}
}

(2)BiFunction<T,U,R> 表示带两个参数且返回一个结果的函数,结果类型可以与参数类型不同,需要覆盖 R apply (T,U) 方法

import java.util.function.*;
public class BiFunctionDemo {
     
     
	public static void main(String[] args) {
     
     
		BiFunction<Float,Float,Float> area = (width,height)-> width*height;
		float width = 2.5F;
		float height = 2.5F;
		float realarea = area.apply(width, height);
		System.out.println("the area is " + realarea);		
	}
}

(3)UnaryOperator 表示一种有一个操作数的运算且返回一个结果,结果类型与操作类型一样。UnaryOperator 是Function 的子接口(用法与Function 类似)
(4)BinaryOperator 表示一种有两个操作数的运算,结果类型必须与操作类型一样,是BiFunction<T,U,R> 的子接口(用法与BiFunction 类似)
(5)Predicate 带一个参数的函数,它基于参数值返回 true 或者 false 值,需要覆盖 test 方法

public interface Predicate<T>{
     
     
	boolean test(T t);
}
//判断字符串是否全部为数字
import java.util.function.*;
public class PredicateDemo {
     
     
	public static void main(String[] args) {
     
     
		Predicate<String> numbersonly = (input)->{
     
     
			for(int i= 0;i<input.length();i++) {
     
     
				char c = input.charAt(i);
				if("0123456789".indexOf(c)==-1)
					return false;
			}
			return true;
		};
		System.out.println(numbersonly.test("123456"));
		System.out.println(numbersonly.test("100o1"));
		
	}
}

(6)Supplier 表示结果的提供者 ,需要覆盖 get 方法

//随机生成随机数

import java.util.Random;
import java.util.function.*;
public class SupplierDemo {
     
     
	public static void main(String[]args) {
     
     
		Supplier<Integer> onerandom = ()->{
     
     
			Random random = new Random();
			return random.nextInt(10);
		};
	for(int i = 1;i<=5;i++)
		System.out.println(onerandom.get());
	}
}

(7)Comsumer 带一个参数且不返回结果的操作,需要覆盖 accept 方法

import java.util.function.*;

//带一个字符串参数,并居中对齐输出
public class ConsumerDemo {
     
     
	public static void main(String[]args) {
     
     
		Function<Integer,String> space = (count)->{
     
     
			StringBuilder sb = new StringBuilder(count);
			for(int i =1;i<=count;i++)
				sb.append(" ");
			return sb.toString();
		};
		int lineLength = 60;
		Consumer<String> printCenter = (input)->{
     
     
			int length = input.length();
			String spaces = space.apply((lineLength-length)/2);
			System.out.println(spaces + input);
			
		};
		printCenter.accept("A Lambda expression a day");
		printCenter.accept("makes you");
		printCenter.accept("look smarter");
	}
}

  • 方法引用:java 中许多方法带一个函数式接口对象作为参数,如果传递的表达式有实现的方法,可以使用一种特殊的语法,方法引用来代替Lambda 表达式。
Arrays.sort(names,(x,y)->compareToIgnoreCase(y));//names 为字符串数组
//等价于方法引用
Arrays.sort(names,String::compareToIgnoreCase);
  • 方法引用就是类名或者对象引用,后面跟着::,然后就是方法名。
  • 方法引用有一下三种使用方式:
    (1)对象::实例方法名
    (2)类名::静态方法名
    (3)类名::实例方法名
  • 构造方法引用:构造方法引用与方法引用类似。不同的是构造方法引用需要使用 new 运算符,例如
Employee ::new 

泛型与集合

  • 泛型:类和接口的一种拓展机制,主要是实现参数化类型(泛型又被叫做参数化类型)机制。简单来说,泛型就是带一个或者多个类型参数的类或者接口
  • 泛型的T 不能使用基本的数据类型,如 int ,float,double,boolean ,long,这些基本类型只能由相对应的包装类来代替,分别是Integer,Float,Double,Boolean,Long。T 为类型变量,可以为任何的类或者接口。
  • 泛型的使用与方法的调用类似:方法的调用需要传递参数;使用泛型需要传递一个类型参数,即用某个具体的类型来代替T.
Node<Integer> node = new Node<Integer>(10);//调用构造方法
  • 注意有两个地方要补充 的具体值,如果输入不是预先设定的 类型参数的数据,将会发生编译错误
  • 由于编译器能够从上下文中推断泛型参数的类型,所以在创建泛型类型时,可以直接使用菱形<>语法,即仅用一对尖括号.则上面的代码可以写成:
Node<Integer> node = new Node<>();
  • 类型参数名字使用大写字母表示。常见的类型参数名有 E(表示元素),K(表示键),N(表示数字),T(表示类型),V(表示值)等,注意泛型可能会有多个类型参数,但是在类或者接口的声明中,每个参数名必须是唯一的
  • 当你的类继承接口的时候,你的相对应的类型参数也要保持一致

猜你喜欢

转载自blog.csdn.net/weixin_74850661/article/details/134792098