This question already has answers here:
this: Cannot use this in static context
(5 answers)
Closed 1 year ago.
I am implementing my own generic Linked List class and it has a instance method called toArray that make a array copy of the linked list and return it. However, whenever I try to call that method on an instance I keep getting error message "SLList.this cannot be referenced from a static context". I searched for it for a bit and some people said that it was because I did not call that method on an instance, but I indeed did.
Here is the class:
public class SLList<ElemType>{
private class StuffNode{
public ElemType item;
public StuffNode next;
public StuffNode(ElemType i, StuffNode n){
item = i;
next = n;
}
}
/** The first item of a list(if it exists) is at sentinel.next*/
private StuffNode sentinel;
private int size;
public ElemType[] toArray(){
ElemType[] arr =(ElemType[]) new Object[this.size];
StuffNode ptr = this.sentinel;
int i = 0;
while(ptr.next != null){
arr[i] = ptr.next.item;
ptr = ptr.next;
i++;
}
return arr;
}
}
It has some method like addLast, addFirst and they have no problem.
public static void main(String[] args){
SLList<Integer> x = new SLList<>(3);
x.addLast(4);
x.addFirst(1);
ElemType[] arr = x.toArray();
}
ElemType[] arr = x.toArray(); is the line where I keep getting error message, and I have used a online Java visualizer to confirm that method works just fine, I just have problem returning the result from it
You could do it like this:
public class Main2 {
public static void main(String[] args) {
SLList<Integer> x = new Main2().new SLList<>(3);
x.addLast(4);
x.addFirst(1);
Integer[] arr = x.toArray();
}
public class SLList<ElemType> {
private class StuffNode {
public ElemType item;
public StuffNode next;
public StuffNode(ElemType i, StuffNode n) {
item = i;
next = n;
}
}
public SLList(ElemType n) {
// Some code for constructor
}
public void addFirst(ElemType n) {
// Some code
}
public void addLast(ElemType n) {
// Some code
}
/**
* The first item of a list(if it exists) is at sentinel.next
*/
private StuffNode sentinel;
private int size;
public ElemType[] toArray() {
ElemType[] arr = (ElemType[]) new Object[this.size];
StuffNode ptr = this.sentinel;
int i = 0;
while (ptr.next != null) {
arr[i] = ptr.next.item;
ptr = ptr.next;
i++;
}
return arr;
}
}
}
or like this:
public class Main2 {
public static void main(String[] args) {
SLList<Integer> x = new SLList<>(3);
x.addLast(4);
x.addFirst(1);
Integer[] arr = x.toArray();
}
// INSERT A STATIC HERE
public static class SLList<ElemType> {
private class StuffNode {
public ElemType item;
public StuffNode next;
public StuffNode(ElemType i, StuffNode n) {
item = i;
next = n;
}
}
public SLList(ElemType n) {
// Some code for constructor
}
public void addFirst(ElemType n) {
// Some code
}
public void addLast(ElemType n) {
// Some code
}
/**
* The first item of a list(if it exists) is at sentinel.next
*/
private StuffNode sentinel;
private int size;
public ElemType[] toArray() {
ElemType[] arr = (ElemType[]) new Object[this.size];
StuffNode ptr = this.sentinel;
int i = 0;
while (ptr.next != null) {
arr[i] = ptr.next.item;
ptr = ptr.next;
i++;
}
return arr;
}
}
}
This problem has puzzled me for a long time, please help me,thanks.
This is my java code.
package com.concurrent.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* P683
*/
class CircularSet {
private int[] array;
private int len;
private int index = 0;
public CircularSet (int size) {
array = new int[size];
len = size;
for (int i = 0; i < size; i++) {
array[i] = -1;
}
}
public synchronized void add(int i ) {
array[index] = i;
index = ++index % len;
}
public synchronized boolean contains(int val) {
for (int i = 0; i < len; i++) {
if(array[i] == val) {
return true;
}
}
return false;
}
}
public class SerialNumberChecker {
private static final int SIZE = 10;
private static CircularSet serials = new CircularSet(1000);
private static ExecutorService exec = Executors.newCachedThreadPool();
private static int serial;
static class SerialChecker implements Runnable {
#Override
public void run() {
while(true) {
//int serial;
synchronized (serials) {
serial = SerialNumberGenerator.nextSerialNumber();
}
if (serials.contains(serial)) {
System.out.println("Duplicate: " + serial);
System.exit(0);
}
System.out.println(serial);
serials.add(serial);
}
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < SIZE; i++) {
exec.execute(new SerialChecker());
if (args.length > 0) {
TimeUnit.SECONDS.sleep(new Integer(args[0]));
System.out.println("No duplicates detected");
System.exit(0);
}
}
}
}
It can stop, but when i uncomment //int serial;The result is different,it can't stop.Why does this temporary variable have a different result than the static variable of the external class. Is this the reason of using a thread?
The code of SerialNumberGenerator:
public class SerialNumberGenerator {
private static volatile int serialNumber = 0;
public static int nextSerialNumber() {
return serialNumber ++; //Not thread-safe
}
}
With private static int serial, all SerialNumberCheckers share the same serial. For example:
Thread1 set serial = 1
Thread2 set serial = 2
Thread1 put 2 into CircularSet.
Thread2 found it duplicate and exit.
However, if you declare another int serial in the run method, It will shadow the private static int serial, which means all threads has its own serial and they will assign & check it. Since the generation of serial is in the synchronized block, there will be no duplicates.
I have started experimenting with the Jenetics library, however I am having some issues with trying to make a very easy "custom" set of gene/chromosomes.
What I tried to do was to create a custom chromosome with a different (random) number of custom genes inside. The genes simply contain an integer value, just for the sake of simplicity. For the same simplicity, the contents of a gene can only be numbers ranging from 0 to 9 and a Gene is considered valid only if it does NOT contain the number 9 (again, retardedly simple, but I just wanted to make them custom)
Here is my code:
CustomGene:
public class CustomGene implements Gene<Integer, CustomGene> {
private Integer value;
private CustomGene(Integer value) {
this.value = value;
}
public static CustomGene of(Integer value) {
return new CustomGene(value);
}
public static ISeq<CustomGene> seq(Integer min, Integer max, int length) {
Random r = RandomRegistry.getRandom();
return MSeq.<CustomGene>ofLength(length).fill(() ->
new CustomGene(random.nextInt(r, min, max))
).toISeq();
}
#Override
public Integer getAllele() {
return value;
}
#Override
public CustomGene newInstance() {
final Random random = RandomRegistry.getRandom();
return new CustomGene(Math.abs(random.nextInt(9)));
}
#Override
public CustomGene newInstance(Integer integer) {
return new CustomGene(integer);
}
#Override
public boolean isValid() {
return value != 9;
}
}
CustomChromosome:
import org.jenetics.Chromosome;
import org.jenetics.util.ISeq;
import org.jenetics.util.RandomRegistry;
import java.util.Iterator;
import java.util.Random;
public class CustomChromosome implements Chromosome<CustomGene> {
private ISeq<CustomGene> iSeq;
private final int length;
public CustomChromosome(ISeq<CustomGene> genes) {
this.iSeq = genes;
this.length = iSeq.length();
}
public static CustomChromosome of(ISeq<CustomGene> genes) {
return new CustomChromosome(genes);
}
#Override
public Chromosome<CustomGene> newInstance(ISeq<CustomGene> iSeq) {
this.iSeq = iSeq;
return this;
}
#Override
public CustomGene getGene(int i) {
return iSeq.get(i);
}
#Override
public int length() {
return iSeq.length();
}
#Override
public ISeq<CustomGene> toSeq() {
return iSeq;
}
#Override
public Chromosome<CustomGene> newInstance() {
final Random random = RandomRegistry.getRandom();
ISeq<CustomGene> genes = ISeq.empty();
for (int i = 0; i < length; i++) {
genes = genes.append(CustomGene.of(Math.abs(random.nextInt(9))));
}
return new CustomChromosome(genes);
}
#Override
public Iterator<CustomGene> iterator() {
return iSeq.iterator();
}
#Override
public boolean isValid() {
return iSeq.stream().allMatch(CustomGene::isValid);
}
}
Main:
import org.jenetics.Genotype;
import org.jenetics.Optimize;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.util.Factory;
import org.jenetics.util.RandomRegistry;
import java.util.Random;
public class Main {
private static int maxSum = - 100;
private static Integer eval(Genotype<CustomGene> gt) {
final int sum = gt.getChromosome().stream().mapToInt(CustomGene::getAllele).sum();
if(sum > maxSum)
maxSum = sum;
return sum;
}
public static void main(String[] args) {
final Random random = RandomRegistry.getRandom();
Factory<Genotype<CustomGene>> g =
Genotype.of(CustomChromosome.of(CustomGene.seq(0, 9, Math.abs(random.nextInt(9)) + 1)));
Engine<CustomGene, Integer> engine = Engine
.builder(Main::eval, g)
.optimize(Optimize.MAXIMUM)
.populationSize(100)
.build();
Genotype<CustomGene> result = engine.stream().limit(10000)
.collect(EvolutionResult.toBestGenotype());
System.out.println(eval(result));
result.getChromosome().stream().forEach(i -> {
System.out.print(i.getAllele() + " ");
});
System.out.println();
System.out.println(maxSum);
}
}
I do not understand why I get this output:
13 (evaluated result)
1 8 0 4 (all the alleles form the genes of the chosen chromosome)
32 (the actual maximum fitness found)
We can clearly see a difference between the genotype which had the biggest fitness function and the chosen genotype. Why?
I know I'm doing something wrong and it's probably a silly mistake, but I really can't seem to understand what I am doing wrong. Could you please help me out?
Lots of thanks!
As posted by the creator of the library here, the answer was:
you violated the contract of the Chromosome.newInstance(ISeq) method. This method must return a new chromosome instance. After fixing this
#Override
public Chromosome<CustomGene> newInstance(ISeq<CustomGene> iSeq) {
return new CustomChromosome(iSeq);
}
In Java, the output of s is 0. I do not understand why and would it be possible to somehow get the correct value of s (1000 here)?
public static void main(String args) {
int s = 0;
List<Integer> list = getList(s);
System.out.println("s = " + s);
}
public static List<Integer> getList(int s) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
list.add(i); s++;
}
}
In C# there were out descriptors to indicate that the variable is going to change if I'm not mistaken..
I'm not going to get the list.size() in general!
In Java, all method arguments are passed by value, i.e. copy. So, changes to the copy are not visible to the caller.
To address your second question, you can just use list.size() on the caller side.
I see two ways
1) Make 's' as static variable and move it to class level
2) Create class with getter/setter for list and int and return the object for getList call
public static MyWrapperObj getList(int s) {
......
return wrapperObj
}
class MyWrapperObj
{
private List<Integer>;
private countS;
....
//getter/setters.
}
Java doesn't allow for passing parameters by reference - but you could wrap it in an object like this:
class IntHolder {
private int s;
IntHolder(int s){
this.s = s;
}
public void setS(int s){
this.s = s;
}
public int getS(){
return s;
}
public void increment(){
s++;
}
}
class Test{
public static void main(String[] args) {
IntHolder s = new IntHolder(0);
List<Integer> list = getList(s);
System.out.println("s = " + s.getS());
}
public static List<Integer> getList(IntHolder s) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
list.add(i); s.increment();
}
return list;
}
}
In java, arguments passed to methods are passed by value.. you will need to make s a global or instance variable in order to modify it in other methods. This is just the way java works. e.g.
public class Test{
private int s;
public Test(){
s=0;
increment();
//print now will be 1000.
}
private void increment(){
s = 1000;
}
}
I have a class, and list of instances, that looks something like this (field names changed to protect the innocent/proprietary):
public class Bloat
{
public long timeInMilliseconds;
public long spaceInBytes;
public long costInPennies;
}
public class BloatProducer
{
final private List<Bloat> bloatList = new ArrayList<Bloat>();
final private Random random = new Random();
public void produceMoreBloat()
{
int n = bloatList.size();
Bloat previousBloat = (n == 0) ? new Bloat() : bloatList.get(n-1);
Bloat newBloat = new Bloat();
newBloat.timeInMilliseconds =
previousBloat.timeInMilliseconds + random.nextInt(10) + 1;
newBloat.spaceInBytes =
previousBloat.spaceInBytes + random.nextInt(10) + 1;
newBloat.costInPennies =
previousBloat.costInPennies + random.nextInt(10) + 1;
bloatList.add(newBloat);
}
/* other fields/methods */
public boolean testMonotonicity()
{
Bloat previousBloat = null;
for (Bloat thisBloat : bloatList)
{
if (previousBloat != null)
{
if ((previousBloat.timeInMilliseconds
>= thisBloat.timeInMilliseconds)
|| (previousBloat.spaceInBytes
>= thisBloat.spaceInBytes)
|| (previousBloat.costInPennies
>= thisBloat.costInPennies))
return false;
}
previousBloat = thisBloat;
}
return true;
}
BloatProducer bloatProducer;
The list bloatList is kept internally by BloatProducer and is maintained in such a way that it only appends new Bloat records, does not modify any of the old ones, and each of the fields is monotonically increasing, e.g. bloatProducer.testMonotonicity() would always return true.
I would like to use Collections.binarySearch(list,key,comparator) to search for the Bloat record by either the timeInMilliseconds, spaceInBytes, or costInPennies fields. (and if the number is between two records, I want to find the previous record)
What's the easiest way to write a series of 3 Comparator classes to get this to work? Do I have to use a key that is a Bloat object with dummy fields for the ones I'm not searching for?
You'll need to write a separate comparator for each field you want to compare on:
public class BloatTimeComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
if (bloat1.timeInMilliseconds > bloat2.timeInMilliseconds) {
return 1;
} else if (bloat1.timeInMilliseconds < bloat2.timeInMilliseconds) {
return -1;
} else {
return 0;
}
}
}
And so on for each property in Bloat you want to compare on (you'll need to create a comparator class for each). Then use the Collections helper method:
Collections.binarySearch(bloatList, bloatObjectToFind,
new BloatTimeComparator());
From the Java documentation for the binarySearch method, the return value will be:
the index of the search key, if it is contained in the list; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the list: the index of the first element greater than the key, or list.size() if all elements in the list are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
Which is the index you specified that you wanted.
You will need to have 3 separate Comparators if you want to search by each of the 3 properties.
A cleaner option would be to have a generic Comparator which receives a parameter which tells it by which field to compare.
A basic generic comparator should look something like this:
public class BloatComparator implements Comparator<Bloat>
{
CompareByEnum field;
public BloatComparator(CompareByEnum field) {
this.field = field;
}
#Override
public int compare(Bloat arg0, Bloat arg1) {
if (this.field == CompareByEnum.TIME){
// compare by field time
}
else if (this.field == CompareByEnum.SPACE) {
// compare by field space
}
else {
// compare by field cost
}
}
}
Here's a test-driven approach to writing the first comparator:
public class BloatTest extends TestCase{
public class Bloat {
public long timeInMilliseconds;
public long spaceInBytes;
public long costInPennies;
public Bloat(long timeInMilliseconds, long spaceInBytes, long costInPennies) {
this.timeInMilliseconds = timeInMilliseconds;
this.spaceInBytes = spaceInBytes;
this.costInPennies = costInPennies;
}
}
public void testMillisecondComparator() throws Exception {
Bloat a = new Bloat(5, 10, 10);
Bloat b = new Bloat(3, 12, 12);
Bloat c = new Bloat(5, 12, 12);
Comparator<Bloat> comparator = new MillisecondComparator();
assertTrue(comparator.compare(a, b) > 0);
assertTrue(comparator.compare(b, a) < 0);
assertEquals(0, comparator.compare(a, c));
}
private static class MillisecondComparator implements Comparator<Bloat> {
public int compare(Bloat a, Bloat b) {
Long aTime = a.timeInMilliseconds;
return aTime.compareTo(b.timeInMilliseconds);
}
}
}
If you want to leverage the binary search for all three properties, you have to create comparators for them and have additional Lists or TreeSets sorted by the comparators.
test program (MultiBinarySearch.java) to see if these ideas work properly (they appear to):
package com.example.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
class Bloat
{
final public long timeInMilliseconds;
final public long spaceInBytes;
final public long costInPennies;
static final private int N = 100;
public Bloat(long l1, long l2, long l3) {
timeInMilliseconds = l1;
spaceInBytes = l2;
costInPennies = l3;
}
public Bloat() { this(0,0,0); }
public Bloat moreBloat(Random r)
{
return new Bloat(
timeInMilliseconds + r.nextInt(N) + 1,
spaceInBytes + r.nextInt(N) + 1,
costInPennies + r.nextInt(N) + 1
);
}
public String toString() {
return "[bloat: time="+timeInMilliseconds
+", space="+spaceInBytes
+", cost="+costInPennies
+"]";
}
static int compareLong(long l1, long l2)
{
if (l2 > l1)
return -1;
else if (l1 > l2)
return 1;
else
return 0;
}
public static class TimeComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.timeInMilliseconds, bloat2.timeInMilliseconds);
}
}
public static class SpaceComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.spaceInBytes, bloat2.spaceInBytes);
}
}
public static class CostComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.costInPennies, bloat2.costInPennies);
}
}
enum Type {
TIME(new TimeComparator()),
SPACE(new SpaceComparator()),
COST(new CostComparator());
public Comparator<Bloat> comparator;
Type(Comparator<Bloat> c) { this.comparator = c; }
}
}
class BloatProducer
{
final private List<Bloat> bloatList = new ArrayList<Bloat>();
final private Random random = new Random();
public void produceMoreBloat()
{
int n = bloatList.size();
Bloat newBloat =
(n == 0) ? new Bloat() : bloatList.get(n-1).moreBloat(random);
bloatList.add(newBloat);
}
/* other fields/methods */
public boolean testMonotonicity()
{
Bloat previousBloat = null;
for (Bloat thisBloat : bloatList)
{
if (previousBloat != null)
{
if ((previousBloat.timeInMilliseconds
>= thisBloat.timeInMilliseconds)
|| (previousBloat.spaceInBytes
>= thisBloat.spaceInBytes)
|| (previousBloat.costInPennies
>= thisBloat.costInPennies))
return false;
}
previousBloat = thisBloat;
}
return true;
}
public int searchBy(Bloat.Type t, Bloat key)
{
return Collections.binarySearch(bloatList, key, t.comparator);
}
public void showSearch(Bloat.Type t, Bloat key)
{
System.out.println("Search by "+t+": ");
System.out.println(key);
int i = searchBy(t,key);
if (i >= 0)
{
System.out.println("matches");
System.out.println(bloatList.get(i));
}
else
{
System.out.println("is between");
i = -i-1;
Bloat b1 = (i == 0) ? null : bloatList.get(i-1);
System.out.println(b1);
Bloat b2 = (i >= bloatList.size()) ? null : bloatList.get(i);
System.out.println("and");
System.out.println(b2);
}
}
}
public class MultiBinarySearch {
private static int N = 1000;
public static void main(String[] args)
{
BloatProducer bloatProducer = new BloatProducer();
for (int i = 0; i < N; ++i)
{
bloatProducer.produceMoreBloat();
}
System.out.println("testMonotonicity() returns "+
bloatProducer.testMonotonicity());
Bloat key;
key = new Bloat(10*N, 20*N, 30*N);
bloatProducer.showSearch(Bloat.Type.COST, key);
bloatProducer.showSearch(Bloat.Type.SPACE, key);
bloatProducer.showSearch(Bloat.Type.TIME, key);
key = new Bloat(-10000, 0, 1000*N);
bloatProducer.showSearch(Bloat.Type.COST, key);
bloatProducer.showSearch(Bloat.Type.SPACE, key);
bloatProducer.showSearch(Bloat.Type.TIME, key);
}
}