Feb 1997

Overtime and overdue


  • Home

  • Tags

  • Categories

  • Archives

  • Search

Java:泛型

Posted on 2019-10-21 Edited on 2020-05-26 In Java

问题引入

第一次在《Java编程思想》中接触到泛型这个概念是在第十一章中,这一章讲的是持有对象。
首先来看一份没有使用泛型的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.ArrayList;

class Apple {
private static long counter;
private final long id = counter++;
public long id() { return id; }
}

class Orange {}

public class ApplesAndOrangesWithoutGenerics {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ArrayList apples = new ArrayList();
for (int i = 0; i < 3; i++)
apples.add(new Apple());
apples.add(new Orange());
for(int i = 0; i < apples.size(); i++)
((Apple)apples.get(i)).id();
}
}

代码分析:
首先定义两个类(Apple和Orange),两个类除了都默认继承自Object类之外没有任何共性。
主函数中尝试将三个Apple对象和一个Orange对象放入容器ArrayList apples中,使用了@SuppressWarnings注解及其参数表示只有有关“不受检查的异常”的警告信息应该被抑制。
最后一个for循环用于获取容器apples中的对象的id。
运行结果:
报错信息holding.Orange cannot be cast to holding.Apple,Orange类型不能转型为Apple类型

然后来看一份使用了泛型的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.ArrayList;

public class ApplesAndOrangesWithGenerics {
public static void main(String[] args) {
ArrayList<Apple> apples = new ArrayList<Apple>();
for (int i = 0; i < 3; i++)
apples.add(new Apple());
// apples.add(new Orange());
for (int i = 0; i < apples.size(); i++)
System.out.println(apples.get(i));
for (Apple c : apples)
System.out.println(c.id());
}
}

代码分析:
执行的操作和之前的代码一样,区别在于初始化容器时ArrayList后面加了一个<Apple>,尖括号括起来的是类型参数(可以有多个),它指定了这个容器实例可以保存的类型。在此处我将添加Orange对象到容器注释掉了,因为它在编译期就会报错,而上一份代码在运行时才能看出错误。

个人理解(2019-10-21)

因为目前还没有对泛型进行深入的学习,所以仅仅通过上面的代码我个人对泛型的理解类似于方法的形参,编译期就规定好了容器内对象的类型,这样可以减少运行时错误(变成编译期错误)。并且注意到在将元素从List中取出时,类型转换也不再是必须的了。因为List知道它保存的是什么类型,因此它会在调用get()时替你执行转型。这样,通过使用泛型,你不仅知道编译器将会检查你放置到容器中的对象类型,而且在使用容器中的对象时,可以使用更加清晰的语法。
后续深入学习泛型后再做补充。


Q. Do you know Generics? How did you used in your coding?

Generics allows type (Integer, String, … etc and user defined types) to be a parameter to methods, classes and interfaces. For example, classes like HashSet, ArrayList, HashMap, etc use generics very well.

Advantages

  • Type-safety: We can hold only a single type of objects in generics. It doesn’t allow to store other objects.
  • Type Casting: There is no need to typecast the object.
  • Compile-Time Checking: It is checked at compile time so problem will not occur at runtime.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/** 
* A Simple Java program to show multiple
* type parameters in Java Generics
*
* We use < > to specify Parameter type
*
**/
class GenericClass<T, U> {
T obj1; // An object of type T
U obj2; // An object of type U

// constructor
GenericClass(T obj1, U obj2) {
this.obj1 = obj1;
this.obj2 = obj2;
}

// To print objects of T and U
public void print() {
System.out.println(obj1);
System.out.println(obj2);
}
}

// Driver class to test above
class MainClass {
public static void main (String[] args) {
GenericClass <String, Integer> obj =
new GenericClass<String, Integer>("Generic Class Example !", 100);

obj.print();
}
}

Output:

1
2
Generic Class Example !
100

↥ back to top

Java:Lambda表达式

Posted on 2019-10-19 Edited on 2019-10-20 In Java

问题引入

今天在学习过程中写了这样一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Game { boolean move(); }
interface GameFactory { Game getGame(); }

class Checkers implements Game {
private int moves = 0;
private static final int MOVES =3;

@Override
public boolean move() {
System.out.println("Checkers move " + moves);
return ++moves != MOVES;
}

public static GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Checkers();
}
};
}

此时编译器在new GameFactory()处提醒 Anonymous new GameFactory() can be replaced with lambda。点击后整个方法块被public static GameFactory factory = () -> new Checkers();所替代,这就是lambda表达式。

Lambda表达式

Lambda表达式,也可称为闭包,它是推动Java 8 发布的最重要新特性。
Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda表达式可以是代码变的更加简洁紧凑。

语法

Lambda表达式的语法格式如下:

1
2
3
(parameters) -> expression
或
(parameters) ->{ statements; }

根据语法回到之前的例子:public static GameFactory factory = () -> new Checkers();表示的就是不需要参数,返回值为一个Checkers对象。

Java:内部类

Posted on 2019-10-17 In Java

可以将一个类的定义放在另一个类的定义内部,这就是内部类。

Note:SYSC5105

Posted on 2019-10-06 Edited on 2020-08-10

Three conditions necessary to observe the failure
Reachability: The location(s) in the program that contain fault must be reached
Infection: The state of the program must be incorrect
Propagation: The infected state must be propagated to cause some unexpected result/output

Observability: How easy to observe the behavior of a program in terms of the outputs, effect on the environment including hardware and software components
Controllability: How easy it is to proveid a program with the needed inputs

Test driver: executes a test case or a test suite/set
Stub: replaces a called component, simulates a piece of code not yet ready
Oracle: assists in deciding whether a test outcome is successful or not, comparing the actual output against expected output; deciding what output is expected, given the test inputs of a test case

Tech to reduce the number of inputs:
Testing criteria group input elements into classes
One input is selected in each class
Criteria are used to decide which test inputs to use
Criteria are used to decide when to stop testing

Black box:
Scales up - works for a function/class/system/packet
Don’t know how much of the system is being tested
White box:
Based on control and data flow
Not Scales up - mostly applicable at unit and integration testing levels
Be confident about how much of the system is being tested

Selection criterion:
generate values to satisfy the criterion
Coverage criterion:
Evaluate coverage achieved by externally generated test values/ cases

Verification:
The process of evaluating a system or component to determine whether the products of a given development phase satisfies the conditions imposed at the start of that phase.
Checking whether the system adheres to properties termed as verification properties
Validation:
The process of evaluating a system or component during or at the end of the development process to determine whether it satisfies specified requirements.

Fault: a deficit in a system
Error: some part of the system entered an unexpected state
Failure: the delivered service deviated from what the system is intended for

Java:String,StringBuffer和StringBuilder

Posted on 2019-09-25 Edited on 2019-10-04 In Java

String

源码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public String() {
this.value = "".value;
}

/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/

String类中每一个看起来会修改String值得方法,实际上都是创建了一个全新的String对象。每当把String对象作为方法的参数时,都会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置上。这就是为什么我们说String类是不可变的(immutable)。

StringBuffer

源码分析:
定义:

1
2
3
4
5
6
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
...
}

StringBuffer类被final修饰,因此不能继承。
此类的父类是AbstractStringBuilder,AbstractStringBuilder类中具体实现了可变字符序列的一系列操作,比如append()、insert()、delete()、replace()、charAt()方法等。
此类实现了两个接口,Serializable表示该类的对象可以被序列化,CharSequence的接口提供了几个对字符序列进行只读访问的方法,例如length()、charAt()、subSequence()、toString()方法等。

主要变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;

// AbstractStringBuilder.java

/**
* The value is used for character storage.
*/
char[] value;

/**
* The count is the number of characters used.
*/
int count;

  1. toStringCache用来缓存toString()方法返回的最近一次的value数组中的字符。当修改StringBuffer对象时会被清除。
  2. value用来存储字符序列中的字符。这是一个动态数组,当存储容量不足时,会对它进行扩容。

    1
    2
    3
    AbstractStringBuilder(int capacity) {
    value = new char[capacity];
    }
  3. count表示value数组中已存储的字符数。
    StringBuffer类将所有操作字符序列的方法都添加了 synchronized 关键字来修饰,因此,StringBuffer类是线程安全的。

StringBuilder

StringBuilder和StringBuffer的源码中,定义和操作几乎都是一样的,唯一的区别是StringBuffer是线程安全的,在单线程的情况下StringBuilder比StringBuffer要快。

LeetCode: 1.Two Sum

Posted on 2019-09-20 Edited on 2019-11-06 In LeetCode

Problem Description

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Wrong Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
int[] res = new int[2];
for (int i =0; i <nums.length; i++){
hashMap.put(nums[i], i);
if(hashMap.containsKey(target-nums[i])){
res[0] = i;
res[1] = hashMap.get(target-nums[i]);
}
}
return res;
}
}

Error Information

When nums= [3, 3], target = 6,expected outcome is[0, 1],but [1, 1].

Wrong Thinking

I was trying to store the array into a hashmap. Considering that hashmap can only get value from key, so I put the value of array at the place of K while incremental i is V.
Then reason why I was wrong was not considering the situation of repeated numbers. During the debugging I found that the size of hashMap is 1 when the nums=[3,3] which means key is unique in hashMap.

How Did I Correct the Code

Review

The key of making mistake is ignoring the situation of repeated numbers in array, so directely transform array into hashmap by reversing the index to value is not feasible since the repeated numbers won’t be stored twice in hashmap as a key.

Analysis

Given that the input would have exactly one solution, and the same element won’t be used twice, situation like multi-resolution and non-resolution will not be considered.
Because hashMap can get value by key, we still need hashmap to do this but in another way.
Instead of transforming the array into hashmap one time, I decide to use hashMap.containskey(target-nums[i]) to search the hashmap, if returns false, then I put this number into the hashmap instead, otherwise we can get the right answer.
If the number is repeated but still cannot find the answer, then it means the resolution is not unique which doesn’t obey the rule of question. For example: nums = [3, 3, 6], target = 9. Obviously, the solution is not unique.

Right Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
int[] res = new int[2];
for (int i = 0; i < nums.length; i++){
if (hashMap.containsKey(target-nums[i])){
res[0] = hashMap.get(target - nums[i]);
res[1] = i;
}else {
hashMap.put(nums[i], i);
}
}
return res;
}

Java:valueOf()方法

Posted on 2019-09-17 Edited on 2019-09-23 In Java

问题引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Main {
public static void main(String[] args) {
// 这里应该输出两个true,实际输出的却是两个false
// 请查找、思考并修复numberEquals方法中的问题
System.out.println(numberEquals("1234", "+1234"));
System.out.println(numberEquals("1234", "1234"));
}

// 判断两个字符串是否包含相等的数字
// 例如a为"+1234",b为"1234",返回true
public static boolean numberEquals(String a, String b) {
return Integer.valueOf(a) == Integer.valueOf(b);
}
}

问题分析

通过查看valueOf()方法的源码查看方法的实现:

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

Integer的作者在写这个类时,为了避免重复创建对象,对Integer值做了缓存,如果输入的整型参数在[IntegerCache.low, IntegerCache.high]内,那么直接返回缓存好的对象,反之new一个新的对象Integer()。
那么缓存的内容是什么呢?看一下IntegerCache这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];

static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}

private IntegerCache() {}
}

以上代码中首先检查虚拟机里有没有相应的配置,如果有,取该值,反之取默认的127。然后创建缓存数组,并给数组初始化值。这是一个内部静态类,该类只能在Integer这个类的内部访问,这个类在初始化的时候,回去加载JVM的配置,如果有值,就用配置的值初始化缓存数组,否则就缓存-128到127之间的值。

问题解决

把valueOf()方法替换成parseInt()方法即可,parseInt()返回的是基本类型int。

Python踩坑:Pycharm中使用Pytorch

Posted on 2019-09-16

问题描述

尝试使用pip install pytorch指令在pycharm中使用Pytorch框架失败

问题解决

在anaconda中使用conda install pytorch torchvision cudatoolkit=10.0 -c pytorch指令安装pytorch后,再在Pycharm中创建新project的时候使用anaconda的环境即可

其他问题

最近Anaconda官网上好像只能下载到3.7版本的了,所以在此之前我创建了一个版本为3.6的虚拟环境(py36),因此在创建project时导入anaconda的环境需要导入虚拟环境目录下的python文件(D:\Anaconda3\envs\py36\python.exe)

Java:静态代码块、非静态代码块、构造函数以及Java类初始化顺序

Posted on 2019-09-07 Edited on 2020-05-30 In Java

问题引入

  今天在做笔试题时遇到这样一个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
static Test t1 = new Test();
{
System.out.println("blockA");
}
static
{
System.out.println("blockB");
}
public static void main(String[] args)
{
Test t2 = new Test();
}
}

  在以上代码中涉及到了静态代码块、构造代码块,之前没接触过这个概念,所以查资料记录学习了一下。

静态代码块

什么是静态代码块?

写法:

1
2
3
4
static
{

}

它有什么特点?

  • 用static申明,JVM加载类时执行,仅执行一次,执行完成便销毁。
  • 静态代码块的执行优先级高于非静态的初始化块。

构造代码块

什么是构造代码块?

写法:

1
2
3
{

}

它有什么特点?

  构造代码块的作用是给对象进行初始化,只有当对象创建才会执行,且执行顺序优于构造函数。并且不同于构造函数,构造代码块针对所有的对象,而构造函数针对对应的对象。

构造函数

  构造函数只有在建立对象的时候在会调用与之相应的构造函数,不建立对象是不会运行构造函数的。一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次。

总结

  1. 静态块其实就是给类初始化的,而构造代码块是给对象初始化的。
  2. 静态代码块只会运行一次
  3. 静态块中的变量是局部变量,与普通函数中的局部变量性质没有区别。
  4. 一个类中可以有多个静态代码块,执行顺序按照位置决定。
  5. 执行顺序优先级:静态块>main()>构造块>构造方法

回到上面的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
static Test t1 = new Test();
{
System.out.println("blockA");
}
static
{
System.out.println("blockB");
}
public static void main(String[] args)
{
Test t2 = new Test();
}
}

输出:

1
2
3
blockA
blockB
blockA

分析:
  t1也是静态变量,所以按照声明顺序执行,先创建对象t1,运行其构造代码块,输出blockA,之后运行静态代码块,输出blockB,最后运行main函数。


创建对象时得调用顺序:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器

Java:接口

Posted on 2019-09-06 Edited on 2019-10-14 In Java

Java中的多重继承

在C++中,组合多个类的接口的行为被称作多重继承。
接口可以解决Java不能多继承的问题

1…8910…12
Feb 1997

Feb 1997

112 posts
4 categories
24 tags
© 2020 Feb 1997