基础知识
- 访问控制
不同修饰符的访问范围
访问范围 | private | default | protected | public |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中 | √ | √ | √ | |
不同包子类 | √ | √ | ||
全局 | √ |
- 封装
类的封装是指把类的状态信息隐藏在类的内部,不允许外部直接访问,而是通过该类提供的方法操作类的内部信息。
类的属性设置为private私有化,外界访问只能通过setter和getter方法进行操作。
类似以下可以对类里的私有属性进行操作,方法中间可加一些合法性校验。
public class Student {
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
if (age>0 && age<200){
this.age = age;
}else {
System.out.println("年龄范围不正确");
}
}
}
- 构造方法
public class Student {
private String name;
private int age;
/**
* 构造方法
* 方法名必须和类名一致
* 构造方法不能写返回值类型
* 构造方法不能使用return返回结果
*
*/
//无参构造方法,
public Student(){
}
//有参构造方法
public Student(String name,int age){
//带this代表成员变量
this.name = name;
this.age = age;
}
}
对象创建
/**
*构造方法在对象创建时自动调用,通过new关键字调用
*
* 作用:可在创建对象的同时进行属性的赋值
*
* 注意:如果没有写构造方法,系统会提供一个无参的构造方法,如果写了构造方法,系统则不会提供构造方法。
*/
Student stu = new Student("李四",15);
- 构造方法重载
一般提供至少两个构造方法(空参、全参的)。
public class Student {
public Student(){
}
public Student(String name){
this.name = name;
}
public Student(String name,int age){
//带this代表成员变量
this.name = name;
this.age = age;
}
}
- this 关键字
在成员变量与局部变量发生重名时,需要使用this关键字区分成员变量和局部变量。
主要用法:
①使用this关键字调用本类中的属性。
this.name
②this关键字调用成员方法。
//若调用本类的,可以省略this不写
this.method();
③调用本类的构造方法。
//调用空参的构造方法
//this()调用构造方法只能放在构造方法的第一行。
this();
- static关键字
如果希望某些属性被所有对象共享,则必须将其声明为static属性。
若属性使用static关键字修饰,则该属性可以直接通过类名调用。
除了修饰属性,还可以修饰成员方法。
static修饰静态方法除了(对象.方法)多了一种(类名.方法)的方式调用。 - 静态代码块
当加载到内存时(对象在被使用时),静态代码会执行,且只执行一次。
public class Student {
static {
System.out.println("数据加载...");
}
}
- 继承
①让类与类之间产生父子关系。
②可以继承父类的私有成员,提高代码复用性。
③子类亦可以定义自己特有的属性。
关键字: extends
如果一个类没有写继承关系,则默认继承Object类,Object为最顶级类。
注意:一个类不能继承多个父类,多个类可以继承一个父类。
class Parent{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
class Sub1 extends parent{
}
class Sub2 extends parent{
}
使用
Sub1 sub = new Sub1();
sub.setName("小狗");
System.out.println(sub.getName());
10.方法重写
①在子父关系中,父类无法满足子类时使用。
②子类可以对父类方法进行重写。
③子类重写父类方法时,访问权限只能大于等于父类。
class Parent{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public void eat(){
System.out.println("吃饭");
}
}
class Sub1 extends Parent{
@Override
public void eat(){
System.out.println("我在吃饭");
}
}
class Sub2 extends Parent{
@Override
public void eat(){
System.out.println("你在吃饭");
}
}
- super关键字
子类重写父类方法后,子类将无法访问父类重写的方法,super关键字可以让子类能够调用父类的普通属性、方法、构造方法。
注意:this和supper不能共存。
class Parent{
private String name;
int num = 1;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public void eat(){
System.out.println("吃饭");
}
}
class Sub1 extends Parent{
@Override
public void eat(){
System.out.println("我在吃饭");
}
}
class Sub2 extends Parent{
public Sub2(){
//调用父类构造方法,可带参进行父类属性赋值
super();
}
@Override
public void eat(){
//调用父类中的num
System.out.println(super.num);
//调用父类方法
super.eat();
System.out.println("你在吃饭");
}
}
-
final关键字。可以用于声明类、属性、方法。
①使用final修饰的类不能有子类(子类不能继承、但自己可以去继承别的类)。
②使用final修饰的方法不能被子类重写。
③使用final修饰的变量(成员、局部变量)是常量,常量不能修改。 -
抽象类。
①抽象方法定义时不需要实现方法体。
②一个类包含了抽象方法,该类必是抽象类。
③子类继承抽象类有抽象方法,子类必须继承所有抽象方法。
④private不能与abstract一起使用。
⑤抽象类不能直接new对象(抽象类中可能有抽象方法)。 -
接口。
接口使用interface关键字声明。
可用(接口名.xxx)方式调用。
语法格式 :
[public] interface 接口名 [extends 接口1,接口2...]{
[public] [static] [final] 类型 常量名 = 常量;
//子类必须要重写
[public] [abstract] 类型 方法名(参数列表);
//jdk8后支持以下,子类不强制进行重写。
[public] static 类型 方法名(参数列表){}
[public] default 类型 方法名(参数列表){}
}
- 多态
①方法重载。
②对象的多态性(方法重写)。
多态:事物表现的不同形态。
前提:
一、必须有继承或实现关系。
二、必须有方法重写。
三、必须有父类指向子类对象。
好处:提高方法灵活性。
可以这样写:
public class Test {
public static void main(String[] args) {
//父类引用指向子类对象。
Fu n = new Z1();
n.eat();
}
}
abstract class Fu{
public abstract void eat();
}
class Z1 extends Fu{
@Override
public void eat() {
System.out.println("你在吃饭");
}
}
class Z2 extends Fu{
@Override
public void eat() {
System.out.println("我在吃饭");
}
}
或者这样写:
public class Test {
public static void main(String[] args) {
//父类引用指向子类对象。
// Fu f = new Z1();
// f.eat();
Z1 z1 = new Z1();
useZ1(z1);
}
public static void useZ1(Z1 z1){
z1.eat();
}
public static void useZ1(Z2 z2){
z2.eat();
}
}
abstract class Fu{
public abstract void eat();
}
class Z1 extends Fu{
@Override
public void eat() {
System.out.println("你在吃饭");
}
}
class Z2 extends Fu{
@Override
public void eat() {
System.out.println("我在吃饭");
}
}
通用方法:
public class Test01 {
public static void main(String[] args) {
Z1 z1 = new Z1();
Z2 z2 = new Z2();
useFu(z1);
useFu(z2);
}
//使用父类,可接受任何子类对象。
public static void useFu(Fu f){
f.eat();
}
}
abstract class Fu{
public abstract void eat();
}
class Z1 extends Fu{
@Override
public void eat() {
System.out.println("你在吃饭");
}
}
class Z2 extends Fu{
@Override
public void eat() {
System.out.println("我在吃饭");
}
}
- 对象类型转换。
①向上转型:子类->父类(自动完成);
②向下转型:父类->子类(必须指定子类对象);
场景:
多态无法使用子类的成员。
需要使用子类成员需要向下转型:
子类对象 对象名 = (子类)父类对象;
instanceof关键字
前面向下转型类型转换可能传入其他子类对象而导致对象转换失败。
if(对象名 instanceof Z1){
//判断可以转换的对象,对应对象的操作。
}
-
Object类
①所有类的父类,每个类都直接或间接继承该类。
②常用方法:
boolran equals()//判断两个对象是否相等,默认比较内存地址,可重写判断属性值。
int hashCode()//返回对象的哈希码值,默认根据内存地址计算出来的值。
String toString()//返回字符串的对象表示形式。 -
内部类
①成员内部类。
一个类中可定义成员变量、成员方法,还可以定义类,这样的类称为内部类。
成员内部类可以访问外部类所有成员。
使用格式:
外部类名.内部类名 对象名 = new 外部类().new 内部类();
②局部内部类。
也叫方法内部类,指定在某个局部范围中的类,和局部变量一样,都在方法中定义,有效方法只限方法内部。
内部类可以访问不外部类的所有成员变量和方法,而局部内部类中的变量和方法只能在所属方法调用。
创建对象、调用成员都在方法内部进行。
③静态内部类。
在定义上,使用了static关键字修饰了成员内部类,
功能上区别:
静态内部类只能访问外部类的静态成员,通过外部类访问静态内部类成员时,可以跳过外部类直接访问静态内部类。
创建静态内部类基本语法:
外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名();
④匿名内部类。
匿名内部类是没有名称的内部类,调用某方法时,如果该方法的参数是类或者接口类型,除了可以传入一个子类或接口实现类,还可以使用实现接口的匿名内部类作为参数,在匿名内部类中直接完成方法的实现。
传统实现:编写实现类、重写抽象方法、创建实现类对象、将实现类对象作为方法的参数传递。
匿名内部类实现:把传统的4步合成了一步,减少了子类或实现类单独的编写。
基本语法:
new 父类 或 父接口(){
//重写方法。
}