前端学Java:java中类和变量的定义

163 阅读2分钟

   从事前端开发工作快两年了,摸鱼划水之际接触到了java。其实我刚开始觉得学好node.js也能迈向全栈,可是当我逐渐深入学习java之后,才感叹java是如此完美的语言。java的强类型,数据结构,IO字节流,多线程以及http网络原理等知识,都应该是衡量一个合格程序员的标准。更何况nodejs作为一门新的单线程后端语言,在国内只有少数的企业才有一席之地,学习好java就更有必要了。

变量的定义

    前端定义变量无非是var,以及es6的let和const, 后来有了typeScript,可以在变量后面带上这个变量的类型。ts也经常被戏称为anyScript,所以即使变量的类型错误或者没有定义类型,运行也不会报错。这样让前端也很难理解到强类型的精髓,而java定义变量的方式,就直 使用类型来定义了。如想定义一个数字类型:

// 整数类型
int a=1;
// 双浮点类型
double c=0.22;
// 字节类型
byte byt=97

   定义一个字符类型:

// 字符
 char b='1';
// 字符串
String c="今天";

     值得注意的是,java中的基本数据有 byte(位)、short(短整数)、int(整数)、long(长整数)、float(单精度)、double(双精度)、char(字符)和boolean(布尔值)。 char是基本数据字符类型,只能用单引号,String字符串引用类型,用双引号。基本数据类型是没有他的引用方法的,因为基本类型跟原始类 Object没有继承关系。所以万物皆对象的说法更适合基于原型的javaScript。再说说java中的包装类,包装类是通过class类new出来的对象,既然是对象,就有他的成员变量和方法。

  将基本类型转化成包装类称为为装箱,将包装类转换为基本类型称为拆箱。 我们可以使用包装类来定义变量,让这个变量可以使用jdk封装好的方法。

Integer a = 11;
int i1 = a.compareTo(4);// 比较数字的大小

Integer num1 = new Integer(1);	// 装箱
int num2 = num1.intValue();	// 拆箱

  java还有很多封装好的类可以直接用来实例化对象:

// 定义一个整数类型的数组,长度为300
int[] array = new int[300];

// 指定数组中的成员
int[] arrA = {30, 65, 33, 67, 66};

// 定义一个成员为字符串类型的ArrarList集合
ArrayList<String> list=new ArrayList<>();

  java定义方法:

// 修饰符 返回值类型 方法名(arg1类型 arg1,arg2类型 arg2)
public void printUpCaseString(String str) {  
  System.out.println(str.toUpperCase());
}

   java中数据类型机制非常庞大,这里不多说了。比起只有数组和对象的javaScript,看起来让人不厌其烦,其实仔细品味,还是很有前瞻性的。下面重点说下自定义类。

类的定义

    java中任何类都继承原始类Object,跟js中的原型类似,所以即使定义一个空的类,也是可以使用Object类上的成员方法的。比如定义一个Person类:

// Person.java
public class Person{}

// 定义主类使用这个类
// PersonTest.java
public class PersonTest {   
 public static void main(String[] args) {    
     Person p1 = new Person();      
  }
}

   类的成员变量是用来修饰对象的,成员变量最好用私有修饰符private来修饰,利于对象的封装省。如果想改变成员变量,可以在类中定义getter和setter。如果只想让其他类取变量值,不想让其他类改变变量值,只定义setter即可。getter和setter就是类的成员方法,一般用public修饰,类似于js中的Object.defineProperty()里面的getter和setter。类还有它的无参构造和有参构造,无参构造默认有一个super方法表明它的继承关系,有参构造则是在实例化对象时,初始化成员变量。

// Person.java
public class Person {   
 private String name;   
// 无参构造
 public Person() { super();   }   
 public Person(String name) {   
     this.name = name;   
 }  
  public String getName() {   
     return name;  
  } 
   public void setName(String name) {   
     this.name = name;   
 }
}
// PersonTest.java
public class PersonTest {   
 public static void main(String[] args) {    
     Person p1 = new Person("小明");
     System.out.println(p1.getName());// 小明
     p1.setName("小光");
     System.out.println(p1.getName());// 小光        }
}

继承和多态

   在学js面向对象的时候,也听说过面向对象的三大特性,封装,继承和多态,对封装和继承有了一定的了解,可是多态是什么意思,学java前还是模棱两可。多态一般需要重写父类的方法,比如猫和狗都继承于动物类,动物类有eat吃东西的方法,但是没有指定吃什么,在猫的类中可以重写eat方法指定吃的是鱼,在狗的类中可以重写eat方法指定吃的是骨头。

// Animal.java
public class Animal {public void eat(){
  System.out.println("吃东西...");
  }
}

// Cat.java
public class Cat extends Animal{

    public void eat(){

        System.out.println("猫吃鱼");
    }
}
// Dog.javapublic class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
 }

public void speak(){
System.out.println("汪汪汪..");
    }
}

// AnimalTest.javapublic class AnimalTest{
public static void main(String[] args) {
   Dog dog=new Dog();
  dog.eat();// 狗吃骨头 }

}

  向上转型:

// AnimalTest.javapublic class AnimalTest{
public static void main(String[] args) {
 Animal animal = new Dog();
  animal.eat();// 狗吃骨头
 }
}

  向上转型时,子类单独定义的方法会丢失。比如给Dog类中单独定义的speak方法,当animal引用指向Dog类实例时是访问不到speak方法的,animal.speak()会报错。

  向下转型:

// AnimalTest.java
public class AnimalTest{
public static void main(String[] args) {
Animal cat = new Cat();
Cat c = ((Cat) cat);
c.eat();// 猫吃鱼

Dog d = ((Dog) cat);// 报错,cat是猫不能转化成狗
d.eat(); 

Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();

 }
}

类成员方法的重写@Override

  @Override是java中的注解,标注改方法是继承父类的方法的重写。Object上toString()返回的是 return getClass().getName() + "@" + Integer.toHexString(hashCode()),也就是这个对象的引用地址,所以对象的引用地址跟它的hashCode有关系。如果没有重写toString(),输出对象默认返回引用地址

// Person.java
public class Person {   
 private String name;   
// 无参构造
 public Person() { super();   }   
 public Person(String name) {   
     this.name = name;   
 }  
  public String getName() {   
     return name;  
  } 
   public void setName(String name) {   
     this.name = name;   
 }
@Override
public String toString() {  
  return "Person{" +      
      "name='" + name + '\'' +       
     '}';
}
}
// PersonTest.java
public class PersonTest {   
 public static void main(String[] args) {    
     Person p1 = new Person("小明");
   //没有重写toString()
     System.out.println(p1);// @b8bfe

  //重写了toString()
    System.out.println(p1);// Person{name='小明'}
}

   还有就是重写equals()和hashCode()方法,这两个方法必须两个一起重写,因为有规约,如果两个对象equals相等,那么它们的hashCode也应该相等。equals 是通过比较两个对象的地址值,hashCode 是将内存地址通过native方法转换成 Int 值来比较。两个不同的对象的hashCode可能相等,也就是hashCode() 相等的两个对象他们的 equal() 不一定相等。java中的Set是存储不重复且没有顺序的集合,先判断hashCode是否相等然后equals()是否相等。

// Person.java
public class Person {   
 private String name;   
// 无参构造
 public Person() { super();   }   
 public Person(String name) {   
     this.name = name;   
 }  
  public String getName() {   
     return name;  
  } 
   public void setName(String name) {   
     this.name = name;   
 }
@Override
public boolean equals(Object o) { 
   if (this == o) return true; 
   if (o == null || getClass() != o.getClass()) return false; 
   Person person = (Person) o;    
  return Objects.equals(name, person.name);
}@Override
public int hashCode() {  
  return Objects.hash(name);
 }}

// PersonTest.java
public class PersonTest {   
 public static void main(String[] args) {    
     Person p1 = new Person("小明");
     Person p2 = new Person("小明");  // 重写equals()之前false,之后为true
   System.out.println(p1.equals(p2));// 没有重写hashCode,会导致equals相等,hashCode不等
  System.out.println(p1.hashCode());
  System.out.println(p2.hashCode());

// 先判断hashCode是否相等然后equals,set去重,必须两个都重写才能去重 Set<Person> set = new HashSet<>(); set.add(p1); set.add(p2);、 for (Person person : set) {    System.out.println(person);
  }}

   这篇文章主要简单地说了下java中类和变量的定义,我会继续努力,深入学习java的数据结构,字节流对象,还有mysql!