java基础(2) —基本语法

越努力越幸运!

一.访问修饰符

               访问权限   类   包  子类  其他包

        public     ∨   ∨    ∨     ∨          (对任何人都是可用的)

        protect    ∨   ∨   ∨     ×    (继承的类可以访问以及和private一样的权限)

        default    ∨   ∨   ×     ×    (包访问权限,即在整个包内均可被访问)

        private    ∨   ×   ×     ×    (除类型创建者和类型的内部方法之外的任何人都不能访问的元素)

二. 抽象类与接口

1.什么是接口?什么是抽象类?区别是什么?

接口是什么?

接口中可以含有 变量和方法。但是要注意,接口中的变量会**被隐式地指定为public static final变量**(并且**只能是public static final变量**,用private修饰会报编译错误),而**方法会被隐式地指定为public abstract方法且只能是public abstract方法**(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。

  可以看出,允许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。

抽象类是什么?

抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

扫描二维码关注公众号,回复: 3429473 查看本文章

  包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

  1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

  2)抽象类不能用来创建对象;

  3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

  在其他方面,抽象类和普通的类并没有区别。

接口与抽象类的区别?

1.语法层面上的区别

  1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

  2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

  3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

  4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2.设计层面上的区别

  1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

  2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

三..封装.继承 多态

封装是什么?

封装就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。

继承是什么?

继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个父类,易于管理程序,父类是子类的一般化,子类是父类的特殊化(具体化),目的是实现代码复用

多态是什么?

同一个类的不同子类对象对同一个方法的调用产生不同的结果叫多态。

多态的前提是:继承,向上转型,重写 

重写与重载

重载是什么?

1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));

2、不能通过访问权限、返回类型、抛出的异常进行重载;

3、方法的异常类型和数目不会对重载造成影响;

4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。

重写是什么?

1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;

4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

重写与重载的区别?

override(重写)

   1、方法名、参数、返回值相同。

   2、子类方法不能缩小父类方法的访问权限。

   3、子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。

   4、存在于父类和子类之间。

   5、方法被定义为final不能被重写。

 overload(重载)

  1、参数类型、个数、顺序至少有一个不相同。 

  2、不能重载只有返回值不同的方法名。

  3、存在于父类和子类、同类中。

四.static

static修饰变量

static修饰的变量是全局变量,也叫做类变量,可以不用创建对象就可以直接使用,与某个类有关,不是和特定的对象有关,static修饰的变量是在类加载中的准备阶段被分配内存,被初始化为0,放在方法区中,在类加载的初始化阶段被初始化为程序员指定的值。

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,

static修饰方法

static修饰的方法叫做静态方法,只能使用静态变量,和调用静态方法。

  声明为static的方法有以下几条限制: 
· 它们仅能调用其他的static 方法。 
· 它们只能访问static数据。 
· 它们不能以任何方式引用this 或super。

因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

static修饰块

static修饰的块就做静态块,静态块在类加载的时候就被加载了,而且只会被加载一次。

static修饰内部类

通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。

五.序列化与反序列化

序列化是什么?

序列化是可以把对象转换成字节流在网络上传输。将一个java对象变成字节流的形式传出去

反序列化是什么?

从一个字节流中恢复成一个java对象。

序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。之后可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输、或者持久化存储到数据库或文件系统中;然后在需要的时候,可以根据字节流中的信息来重构一个相同的对象。序列化机制在java中有着广泛的应用,EJB、RMI等技术都是以此为基础的。

一般而言,要使得一个类可以序列化,只需简单实现java.io.Serializable接口即可(还要实现无参数的构造方法)。该接口是一个标记式接口,它本身不包含任何内容,实现了该接口则表示这个类准备支持序列化的功能。

序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流 

序列化的应用场景?

三种情况下需要进行序列化

1、把对象持久化到文件或数据中
2、在网络上传输
3、进行RMI传输对象时

RPC和RMI都是远程调用,属于中间件技术。RMI是针对于java语言的,它使用的是JRMP协议通信,而RPC是更大众化的,使用http协议传输。

 

static变量会可以序列化吗?

不可以,一个类实现Serializable ,要序列化的时候,static 变量信息是不会被序列化的,要手动的序列化,在一个在同一个程序里保存序列化信息后,马上又读取出来,看不到效果,因为,该序列化的类的原版的static 信息已经加载到内存,所以你看到的很可能就是原版的static 变量。

transient关键字

transient关键字修饰的变量是不被序列化的。

为什么一定要有序列化id?

其版本号id,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

六.泛型—语法糖

什么是泛型?

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。 

在逻辑上Box<Number>不能视为Box<Integer>的父类。

类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且Box<?>在逻辑上是Box<Integer>、Box<Number>...等所有Box<具体类型实参>的父类。由此,我们依然可以定义泛型方法,来完成此类需求

泛型类
只能用在成员变量上,只能使用引用类型
泛型接口
只能用在抽象方法上
泛型方法
返回值前面加上 &ltT&gt


/**
 * 自定义泛型类
 *
 * 定义"模版"的时候,泛型用泛型字母:T 代替
 * 在使用的时候指定实际类型
 *
 * @author Administrator
 * @param <T>
 */
public class Student<T> {
  
  private T javase;
  
  //private static T javaee;   // 泛型不能使用在静态属性上
 
  public Student() {
  }
 
  public Student(T javase) {
    this();
    this.javase = javase;
  }
 
  public T getJavase() {
    return javase;
  }
 
  public void setJavase(T javase) {
    this.javase = javase;
  }
  
}
/**
 * 自定义泛型的使用
 * 在声明时指定具体的类型
 * 不能为基本类型
 * @author Administrator
 *
 */
class Demo02 {
  public static void main(String[] args) {
    //Student<int>  Student = new Student<int>(); //不能为基本类型,编译时异常
    
    Student<Integer> student = new Student<Integer>();
    student.setJavase(85);
    System.out.println(student.getJavase());  
  }
}


/**
 * 自定义泛型接口
 *
 * 接口中泛型字母只能使用在方法中,不能使用在全局常量中
 *
 * @author Administrator
 * @param <T>
 */
public interface Comparator<T1,T2> {
  
  //public static final T1 MAX_VALUE = 100; //接口中泛型字母不能使用在全局常量中
  //T1 MAX_VALUE;
  public static final int MAX_VALUE = 100;
  
  void compare(T2 t);
  T2 compare();
  public abstract T1 compare2(T2 t);
}



import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
 
 
/**
 * 非泛型类中定义泛型方法
 * @author Administrator
 *
 */
public class Method {
 
  // 泛型方法,在返回类型前面使用泛型字母
  public static <T> void test1(T t){
    System.out.println(t);
  }
  
  // T 只能是list 或者list 的子类
  public static <T extends List> void test2(T t){
    t.add("aa");
  }
  
  // T... 可变参数   --->   T[]
  public static <T extends Closeable> void test3(T...a) {
    for (T temp : a) {
     try {
       if (null != temp) {
         temp.close();
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
     
    }
  }
  
  public static void main(String[] args) throws FileNotFoundException {
    test1("java 是门好语言");
    test3(new FileInputStream("a.txt"));
  }
}

泛型的继承
/**
 * 泛型继承
 *
 * 保留父类泛型 ----》泛型子类 
 * 不保留父类泛型 -----》子类按需实现
 *
 * 子类重写父类的方法,泛型类型随父类而定 子类使用父类的属性,该属性类型随父类定义的泛型
 *
 * @author Administrator
 *
 * @param <T1>
 * @param <T2>
 */
public abstract class Father<T1, T2> {
  T1 age;
 
  public abstract void test(T2 name);
}
 
// 保留父类泛型 ----》泛型子类
// 1)全部保留
class C1<T1, T2> extends Father<T1, T2> {
 
  @Override
  public void test(T2 name) {
 
  }
}
 
// 2) 部分保留
class C2<T1> extends Father<T1, Integer> {
 
  @Override
  public void test(Integer name) {
 
  }
}
 
// 不保留父类泛型 -----》子类按需实现
// 1)具体类型
class C3 extends Father<String, Integer> {
 
  @Override
  public void test(Integer name) {
 
  }
}
 
// 2)没有具体类型
// 泛型擦除:实现或继承父类的子类,没有指定类型,类似于Object
class C4 extends Father {
 
  @Override
  public void test(Object name) {
 
  }
 
}



/**
 * 泛型擦除
 * 类似于Object,不等于Object
 * @author Administrator
 *
 */
public class Demo03 {
  
  public static void test(Student<Integer> student){
    student.setJavase(100);
  }
  
  public static void main(String[] args) {
    // 泛型擦除
    Student student = new Student();
    test(student);
    
    Student<Object> student2 = new Student<Object>();
    //test(student2);  //编译异常
  }
 
}
 
通配符
通配符(Wildcards)

T、K、V、E 等泛型字母为有类型,类型参数赋予具体的值
?未知类型 类型参数赋予不确定值,任意类型
只能用在声明类型、方法参数上,不能用在定义泛型类上
/**
 * 泛型的通配符 类型不确定,用于声明变量或者形参上面
 *
 * 不能使用在类上 或者  new 创建对象上
 * @author Administrator
 *
 */
public class Demo04 {
 
  // 用在形参上
  public static void test(List<?> list) {
 
   List<?> list2; // 用在声明变量上
   list2 = new ArrayList<String>();
   list2 = new ArrayList<Integer>();
   list2 = new ArrayList<Object>();
 
  }
 
  public static void main(String[] args) {
   test(new ArrayList<String>());
   test(new ArrayList<Integer>());
  }
 
}

extends/super
上限(extends)
指定的类必须是继承某个类,或者实现了某个接口(不是implements),即<=

? extends List
下限(super)
即父类或本身

? super List
import java.util.ArrayList;
import java.util.List;

/**
 * extends:泛型的上限 <= 一般用于限制操作 不能使用在添加数据上,一般都是用于数据的读取
 *
 * supper:泛型的上限 >= 即父类或自身。一般用于下限操作
 *
 * @author Administrator
 * @param <T>
 */
 
public class Test<T extends Fruit> {
 
  private static void test01() {
    Test<Fruit> t1 = new Test<Fruit>();
    Test<Apple> t2 = new Test<Apple>();
    Test<Pear> t3 = new Test<Pear>();
  }
 
  private static void test02(List<? extends Fruit> list) {
 
  }
 
  private static void test03(List<? super Apple> list) {
 
  }
 
  public static void main(String[] args) {
 
    // 调用test02(),测试 extends  <=
    test02(new ArrayList<Fruit>());
    test02(new ArrayList<Apple>());
    test02(new ArrayList<ReadApple>());
    // test02(new ArrayList<Object>()); Object 不是 Fruit 的子类 ,编译不通过
    
    
    // 调用test03() ,测试super >=
    test03(new ArrayList<Apple>());
    test03(new ArrayList<Fruit>());
    //test03(new ArrayList<ReadApple>());  ReadApple < apple,所以不能放入
  }
 
}
 
class Fruit {
 
}
 
class Apple extends Fruit {
 
}
 
class Pear extends Fruit {
 
}
 
class ReadApple extends Apple {
 
}
        
泛型嵌套
从外向里取

import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
/**
 * 泛型嵌套
 * @author Administrator
 *
 */
public class Demo05 {
 
  
  public static void main(String[] args) {
    Student2<String> student = new Student2<String>();
    student.setScore("优秀");
    System.out.println(student.getScore());
    
    //泛型嵌套
    School<Student2<String>> school = new School<Student2<String>>();
    school.setStu(student);
    
    String s = school.getStu().getScore(); //从外向里取
    System.out.println(s);
    
    // hashmap 使用了泛型的嵌套
    Map<String, String> map =  new HashMap<String,String>();
    map.put("a", "张三");
    map.put("b", "李四");
    Set<Entry<String, String>> set = map.entrySet();
    for (Entry<String, String> entry : set) {
     System.out.println(entry.getKey()+":"+entry.getValue());
    }
    
  }
}




 public class School<T> {
  private T stu;
 
  public T getStu() {
    return stu;
  }
 
  public void setStu(T stu) {
    this.stu = stu;
  }
  
}


 public class Student2<T> {
  T score;
 
  public T getScore() {
    return score;
  }
 
  public void setScore(T score) {
    this.score = score;
  }
}

猜你喜欢

转载自blog.csdn.net/hezuo1181/article/details/82918991